{"record":{"id":"9b324bf581a7bb72","repo":"gchq/CyberChef","slug":"error-loading-image-err-9b324b","errorCode":null,"errorMessage":"Error loading image. (${err})","messagePattern":"Error loading image\\. \\((.+?)\\)","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/DitherImage.mjs","lineNumber":48,"sourceCode":"        this.presentType = \"html\";\n        this.args = [];\n    }\n\n    /**\n     * @param {ArrayBuffer} input\n     * @param {Object[]} args\n     * @returns {byteArray}\n     */\n    async run(input, args) {\n        if (!isImage(input)) {\n            throw new OperationError(\"Invalid file type.\");\n        }\n\n        let image;\n        try {\n            image = await Jimp.read(input);\n        } catch (err) {\n            throw new OperationError(`Error loading image. (${err})`);\n        }\n        try {\n            if (isWorkerEnvironment())\n                self.sendStatusMessage(\"Applying dither to image...\");\n            image.dither();\n\n            let imageBuffer;\n            if (image.mime === \"image/gif\") {\n                imageBuffer = await image.getBuffer(JimpMime.png);\n            } else {\n                imageBuffer = await image.getBuffer(image.mime);\n            }\n            return imageBuffer.buffer;\n        } catch (err) {\n            throw new OperationError(\n                `Error applying dither to image. (${err})`,\n            );\n        }","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/DitherImage.mjs#L30-L66","documentation":"Thrown from the catch block wrapping Jimp.read(input) in DitherImage.run. CyberChef first passes the input through isImage() (a magic-byte sniff), which only checks a file signature and does not validate structural integrity. Jimp.read then fully decodes the bytes, and when decoding fails the underlying Jimp/js-binary-parser error is re-thrown as an OperationError 'Error loading image. (${err})'. The placeholder interpolates Jimp's own message, which usually names the codec that failed (PNG/JPEG/BMP/etc.).","triggerScenarios":"Input passes isImage() because its magic bytes match a recognised image signature, but the file is truncated, corrupted, or has a valid header with malformed pixel data. Also a non-image sharing an image magic number, a zero-length body after a valid header, or a format Jimp's bundled decoders cannot parse (e.g. some TIFF/HEIF variants) reaches Jimp.read and throws.","commonSituations":"Pasting a base64 image whose payload was clipped; a progressive JPEG cut mid-scan; chaining an operation that mutates bytes before DitherImage so the signature survives but the body does not; a very new/obscure container that shares PNG/JPEG magic but is outside Jimp's supported set.","solutions":["Verify the input decodes in an external viewer before feeding DitherImage; if not, fix the source upstream.","If bytes come from a previous operation, inspect that step's output (add Hex dump / Render image) to confirm the body survived.","Ensure the input is one of the formats Jimp decodes (PNG, JPEG, BMP, GIF, TIFF) rather than trusting the magic-byte sniff.","Re-encode the source image to PNG with an external tool and retry."],"exampleFix":"// before: bytes that only share a header\nrun(corruptedBytes, []);\n// after: structurally valid PNG\nrun(await reencodeToPng(originalBytes), []);","handlingStrategy":"validation","validationCode":"// Validate the image decodes fully before DitherImage.\nimport Jimp from \"jimp\";\nasync function isDecodableImage(bytes) {\n  try { await Jimp.read(Buffer.from(bytes)); return true; }\n  catch { return false; }\n}\nif (!(await isDecodableImage(input))) throw new Error(\"input is not a decodable image\");","typeGuard":null,"tryCatchPattern":"try {\n  const out = await dither.run(input, args);\n} catch (e) {\n  if (String(e).includes(\"Error loading image\")) { /* bad input - do not retry */ }\n  else throw e;\n}","preventionTips":["Sniff magic bytes AND attempt a full decode in a pre-validation step before image operations.","Avoid chaining byte-mutating operations immediately before DitherImage.","Reject zero-length or header-only inputs before they reach Jimp.read."],"tags":["image-processing","jimp","input-validation","operation-error"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}