#4607·sharp

keepGainMap(): valid crop throws "extract_area: bad extract area" after resizing a reduced-resolution gain map

Author: gregbenzCreated Sep 17, 2026Updated Sep 17, 2026
Labelstriage

Is this a possible bug in a feature of sharp, unrelated to installation?

[ x] Running npm install sharp completes without error. [ x] Running node -e "import 'sharp'" completes without error.

Are you using the latest version of sharp?

[ x] I am using the latest version of sharp as reported by npm view sharp dist-tags.latest. Running 0.35.4

What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?

System: OS: macOS 27.0 CPU: (18) arm64 Apple M5 Max Memory: 6.47 GB / 128.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 24.18.0 - /Users/redacted/.nvm/versions/node/v24.18.0/bin/node Yarn: 1.22.19 - /usr/local/bin/yarn npm: 11.16.0 - /Users/redacted/.nvm/versions/node/v24.18.0/bin/npm

Does this problem relate to file caching?

[x ] Adding sharp.cache(false) does not fix this problem. Does this problem relate to images appearing to have been rotated by 90 degrees? [x ] Using rotate() or keepExif() does not fix this problem.

What are the steps to reproduce?

run code below, will show error: "extract_area: bad extract area"

Tested against sharp main at commit https://github.com/lovell/sharp/commit/9dcb3ddf27d99b160d1aadafc980c8e42bc4cd1a (reports version 0.35.4), using libvips 8.18.6 and libultrahdr 2.0.2.

What is the expected behaviour?

Expected: the valid crop should save a 30 × 25 JPEG with its gain map preserved and aligned. Actual: the same crop succeeds without keepGainMap(), but with it throws extract_area: bad extract area and produces no usable output image.

Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem

node - "../source images to test/ISO JPG - sRGB - transcoding test - Greg Benz.jpg" <<'NODE'
const sharp = require('sharp');

(async () => {
  // Make a smaller gain map, then save an image with odd dimensions.
  const reduced = await sharp(process.argv[2]).withGainMap().toBuffer();
  const input = './reduced-map-input.jpg';

  await sharp(reduced).keepGainMap()
    .resize(129, 97, { fit: 'fill' })
    .toFile(input);

  // Resize first so sharp crops afterward. The crop fits inside the image.
  const crop = image => image
    .resize(129, 97, { fit: 'fill' })
    .extract({ left: 90, top: 60, width: 30, height: 25 });

  await crop(sharp(input)).toFile('./crop-without-gainmap.jpg');
  console.log('Without keepGainMap: crop succeeds.');

  await crop(sharp(input).keepGainMap())
    .toFile('./crop-with-gainmap.jpg'); // BUG: should save the crop, but throws "extract_area: bad extract area" and produces no usable output image.
})().catch(error => {
  console.error(error.message);
  process.exitCode = 1;
});
NODE

Please provide sample image(s) that help explain this problem

Source to test: Image