lovell/sharp · error · Error

Expected at least two images to join

Error message

Expected at least two images to join

What it means

Thrown when the input to sharp is an array but contains fewer than two elements. The join feature stacks two or more images; a single-element or empty array has nothing to join. Sharp distinguishes this from 'Unsupported input' because the array branch is specifically for joins, and a one-image join is meaningless.

Source

Thrown at lib/input.mjs:102

    inputOptions = input;
    if (_inputOptionsFromObject(inputOptions)) {
      // Stream with options
      inputDescriptor.buffer = [];
    }
  } else if (!is.defined(input) && !is.defined(inputOptions) && is.object(containerOptions) && containerOptions.allowStream) {
    // Stream without options
    inputDescriptor.buffer = [];
  } else if (Array.isArray(input)) {
    if (input.length > 1) {
      // Join images together
      if (!this.options.joining) {
        this.options.joining = true;
        this.options.join = input.map(i => this._createInputDescriptor(i));
      } else {
        throw new Error('Recursive join is unsupported');
      }
    } else {
      throw new Error('Expected at least two images to join');
    }
  } else {
    throw new Error(`Unsupported input '${input}' of type ${typeof input}${
      is.defined(inputOptions) ? ` when also providing options of type ${typeof inputOptions}` : ''
    }`);
  }
  if (is.object(inputOptions)) {
    // failOn
    if (is.defined(inputOptions.failOn)) {
      if (is.string(inputOptions.failOn) && is.inArray(inputOptions.failOn, ['none', 'truncated', 'error', 'warning'])) {
        inputDescriptor.failOn = inputOptions.failOn;
      } else {
        throw is.invalidParameterError('failOn', 'one of: none, truncated, error, warning', inputOptions.failOn);
      }
    }
    // autoOrient
    if (is.defined(inputOptions.autoOrient)) {
      if (is.bool(inputOptions.autoOrient)) {

View on GitHub (pinned to 56676c6918)

Solutions

  1. Ensure the array has at least two valid image inputs before calling sharp.
  2. Guard the length: if (images.length >= 2) sharp(images) else handleSingle(images[0]).
  3. Filter defensively and assert the count before the join call.

Example fix

// before
sharp(images.filter(Boolean), { join: {} })

// after
const valid = images.filter(Boolean);
if (valid.length < 2) throw new Error('need >= 2 images to join');
sharp(valid, { join: {} })
Defensive patterns

Strategy: validation

Validate before calling

function joinInput(images) {
  const valid = images.filter(Boolean);
  if (valid.length < 2) throw new Error(`Join needs >= 2 images, got ${valid.length}`);
  return valid;
}
sharp(joinInput(images), { join: {} });

Type guard

function isJoinableArray(input) {
  return Array.isArray(input) && input.length >= 2;
}

Prevention

When it happens

Trigger: Calling sharp([]) with an empty array, or sharp([singleImage]) with exactly one element. Dynamically building a join list that filters down to one or zero items at runtime: sharp(images.filter(Boolean)) where most are null.

Common situations: Filtering or slicing an image list before joining without checking the resulting length. Off-by-one errors when chunking. Empty result sets from a database query fed directly into sharp.

Related errors


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