lovell/sharp · error · Error
Expected input to be an array of images to join
Error message
Expected input to be an array of images to join
What it means
Thrown when inputOptions.join is provided (join configuration) but this.options.join is not set — meaning there is no array of images to apply the join options to. Join options only make sense alongside a join input; supplying them without a join input is a contract violation. The guard is the else of `if (is.defined(this.options.join))`.
Source
Thrown at lib/input.mjs:515
if (is.defined(inputOptions.join.background)) {
inputDescriptor.joinBackground = this._getBackgroundColourOption(inputOptions.join.background);
}
if (is.defined(inputOptions.join.halign)) {
if (is.string(inputOptions.join.halign) && is.string(this.constructor.align[inputOptions.join.halign])) {
inputDescriptor.joinHalign = this.constructor.align[inputOptions.join.halign];
} else {
throw is.invalidParameterError('join.halign', 'valid alignment', inputOptions.join.halign);
}
}
if (is.defined(inputOptions.join.valign)) {
if (is.string(inputOptions.join.valign) && is.string(this.constructor.align[inputOptions.join.valign])) {
inputDescriptor.joinValign = this.constructor.align[inputOptions.join.valign];
} else {
throw is.invalidParameterError('join.valign', 'valid alignment', inputOptions.join.valign);
}
}
} else {
throw new Error('Expected input to be an array of images to join');
}
}
} else if (is.defined(inputOptions)) {
throw new Error(`Invalid input options ${inputOptions}`);
}
return inputDescriptor;
}
/**
* Handle incoming Buffer chunk on Writable Stream.
* @private
* @param {Buffer} chunk
* @param {string} encoding - unused
* @param {Function} callback
*/
function _write (chunk, _encoding, callback) {
if (Array.isArray(this.options.input.buffer)) {
if (is.buffer(chunk)) {View on GitHub (pinned to 56676c6918)
Solutions
- Only include inputOptions.join when the input is an array of images: sharp([a, b], { join: { ... } }).
- Conditionally add join options only when images.length >= 2.
- Strip join options for single-image pipelines.
Example fix
// before
sharp(singleBuffer, { join: { animated: true } })
// after
sharp([a, b], { join: { animated: true } }) Defensive patterns
Strategy: validation
Validate before calling
function maybeJoin(input, joinOpts) {
if (joinOpts && !Array.isArray(input)) {
throw new Error('join options require an array input of >= 2 images');
}
const opts = Array.isArray(input) && input.length >= 2 ? { join: joinOpts } : {};
return sharp(input, opts);
} Type guard
function joinOptionsApplicable(input, options) {
return !(options && options.join !== undefined) || (Array.isArray(input) && input.length >= 2);
} Prevention
- Only include join options when the input is an array of images.
- Strip join options for single-image pipelines.
- Build options conditionally based on input type.
When it happens
Trigger: sharp(buffer, { join: { animated: true } }) — passing a single buffer input plus join options. sharp('file.png', { join: { halign: 'center' } }) with no array input. Building options from a template that always includes join even when the input is a single image.
Common situations: Reusing an options object across single-image and multi-image code paths. Misunderstanding that join options belong to the array-input form. Auto-generating options where join was conditionally populated for one case but applied to another.
Related errors
- Recursive join is unsupported
- Expected at least two images to join
- Invalid input
- Unsupported input '${input}' of type ${typeof input}${is.def
- Expected width, height and channels for raw pixel input
AI-assisted analysis of lovell/sharp@56676c6918 (2026-08-13).
Data as JSON: /api/errors/107b5fbb75115aee.
Report an issue: GitHub.