lovell/sharp · error · Error

Expected only one of dpi or height

Error message

Expected only one of dpi or height

What it means

Thrown when creating a text image (inputOptions.text) and both text.height and text.dpi are provided. These two control the same thing — output sizing — by different means (fixed pixel height vs dots-per-inch scaling), so specifying both is contradictory. The guard is `is.defined(text.height) && is.defined(text.dpi)`.

Source

Thrown at lib/input.mjs:396

        } else if (is.defined(inputOptions.create.background)) {
          if (!is.inRange(inputOptions.create.channels, 3, 4)) {
            throw is.invalidParameterError('create.channels', 'number between 3 and 4', inputOptions.create.channels);
          }
          inputDescriptor.createBackground = this._getBackgroundColourOption(inputOptions.create.background);
        } else {
          throw new Error('Expected valid noise or background to create a new input image');
        }
        delete inputDescriptor.buffer;
      } else {
        throw new Error('Expected valid width, height and channels to create a new input image');
      }
    }
    // Create a new image with text
    if (is.defined(inputOptions.text)) {
      if (is.object(inputOptions.text) && is.string(inputOptions.text.text)) {
        inputDescriptor.textValue = inputOptions.text.text;
        if (is.defined(inputOptions.text.height) && is.defined(inputOptions.text.dpi)) {
          throw new Error('Expected only one of dpi or height');
        }
        if (is.defined(inputOptions.text.font)) {
          if (is.string(inputOptions.text.font)) {
            inputDescriptor.textFont = inputOptions.text.font;
          } else {
            throw is.invalidParameterError('text.font', 'string', inputOptions.text.font);
          }
        }
        if (is.defined(inputOptions.text.fontfile)) {
          if (is.string(inputOptions.text.fontfile)) {
            inputDescriptor.textFontfile = inputOptions.text.fontfile;
          } else {
            throw is.invalidParameterError('text.fontfile', 'string', inputOptions.text.fontfile);
          }
        }
        if (is.defined(inputOptions.text.width)) {
          if (is.integer(inputOptions.text.width) && is.inRange(inputOptions.text.width, 1, 1000000)) {
            inputDescriptor.textWidth = inputOptions.text.width;

View on GitHub (pinned to 56676c6918)

Solutions

  1. Choose one sizing mode: either text.height (pixel height) or text.dpi (resolution), not both.
  2. When merging configs, delete the unused field: delete opts.height or delete opts.dpi.
  3. For consistent output, prefer height for fixed-size rendering and dpi for resolution-dependent rendering.

Example fix

// before
sharp({ text: { text: 'hello', height: 100, dpi: 72 } })

// after
sharp({ text: { text: 'hello', height: 100 } })
Defensive patterns

Strategy: validation

Validate before calling

function textSize(opts) {
  const { height, dpi, ...rest } = opts;
  if (height !== undefined && dpi !== undefined) {
    throw new Error('text: provide only one of height or dpi, not both');
  }
  return sharp({ text: { ...rest, height, dpi } });
}

Type guard

function textHasSingleSizeMode(text) {
  return !(text.height !== undefined && text.dpi !== undefined);
}

Prevention

When it happens

Trigger: sharp({ text: { text: 'hello', height: 100, dpi: 72 } }). Building a text options object by merging two configs each setting one of the fields.

Common situations: Combining defaults from two sources. Copying examples that each used a different sizing approach. Assuming dpi only affects quality while height affects size (they are mutually exclusive sizing modes).

Related errors


AI-assisted analysis of lovell/sharp@56676c6918 (2026-08-13). Data as JSON: /api/errors/e598e5c56e9e55a1. Report an issue: GitHub.