{"record":{"id":"107b5fbb75115aee","repo":"lovell/sharp","slug":"expected-input-to-be-an-array-of-images-to-join","errorCode":null,"errorMessage":"Expected input to be an array of images to join","messagePattern":"Expected input to be an array of images to join","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/input.mjs","lineNumber":515,"sourceCode":"        if (is.defined(inputOptions.join.background)) {\n          inputDescriptor.joinBackground = this._getBackgroundColourOption(inputOptions.join.background);\n        }\n        if (is.defined(inputOptions.join.halign)) {\n          if (is.string(inputOptions.join.halign) && is.string(this.constructor.align[inputOptions.join.halign])) {\n            inputDescriptor.joinHalign = this.constructor.align[inputOptions.join.halign];\n          } else {\n            throw is.invalidParameterError('join.halign', 'valid alignment', inputOptions.join.halign);\n          }\n        }\n        if (is.defined(inputOptions.join.valign)) {\n          if (is.string(inputOptions.join.valign) && is.string(this.constructor.align[inputOptions.join.valign])) {\n            inputDescriptor.joinValign = this.constructor.align[inputOptions.join.valign];\n          } else {\n            throw is.invalidParameterError('join.valign', 'valid alignment', inputOptions.join.valign);\n          }\n        }\n      } else {\n        throw new Error('Expected input to be an array of images to join');\n      }\n    }\n  } else if (is.defined(inputOptions)) {\n    throw new Error(`Invalid input options ${inputOptions}`);\n  }\n  return inputDescriptor;\n}\n\n/**\n * Handle incoming Buffer chunk on Writable Stream.\n * @private\n * @param {Buffer} chunk\n * @param {string} encoding - unused\n * @param {Function} callback\n */\nfunction _write (chunk, _encoding, callback) {\n  if (Array.isArray(this.options.input.buffer)) {\n    if (is.buffer(chunk)) {","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/lovell/sharp/blob/56676c69180a32b468123e090f87bfee30539b49/lib/input.mjs#L497-L533","documentation":"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))`.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nsharp(singleBuffer, { join: { animated: true } })\n\n// after\nsharp([a, b], { join: { animated: true } })","handlingStrategy":"validation","validationCode":"function maybeJoin(input, joinOpts) {\n  if (joinOpts && !Array.isArray(input)) {\n    throw new Error('join options require an array input of >= 2 images');\n  }\n  const opts = Array.isArray(input) && input.length >= 2 ? { join: joinOpts } : {};\n  return sharp(input, opts);\n}","typeGuard":"function joinOptionsApplicable(input, options) {\n  return !(options && options.join !== undefined) || (Array.isArray(input) && input.length >= 2);\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["join","input","validation","options-mismatch"],"backgroundTag":null,"analyzedSha":"56676c69180a32b468123e090f87bfee30539b49","analyzedAt":"2026-08-13T04:44:31.201Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}