{"record":{"id":"8b8fcde5c28bb5e2","repo":"gchq/CyberChef","slug":"invalid-diff-by-option","errorCode":null,"errorMessage":"Invalid 'Diff by' option.","messagePattern":"Invalid 'Diff by' option\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/Diff.mjs","lineNumber":117,"sourceCode":"                break;\n            case \"Line\":\n                if (ignoreWhitespace) {\n                    diff = jsdiff.diffTrimmedLines(samples[0], samples[1]);\n                } else {\n                    diff = jsdiff.diffLines(samples[0], samples[1]);\n                }\n                break;\n            case \"Sentence\":\n                diff = jsdiff.diffSentences(samples[0], samples[1]);\n                break;\n            case \"CSS\":\n                diff = jsdiff.diffCss(samples[0], samples[1]);\n                break;\n            case \"JSON\":\n                diff = jsdiff.diffJson(samples[0], samples[1]);\n                break;\n            default:\n                throw new OperationError(\"Invalid 'Diff by' option.\");\n        }\n\n        for (let i = 0; i < diff.length; i++) {\n            if (diff[i].added) {\n                if (showAdded) output += \"<ins>\" + Utils.escapeHtml(diff[i].value) + \"</ins>\";\n            } else if (diff[i].removed) {\n                if (showRemoved) output += \"<del>\" + Utils.escapeHtml(diff[i].value) + \"</del>\";\n            } else if (!showSubtraction) {\n                output += Utils.escapeHtml(diff[i].value);\n            }\n        }\n\n        return output;\n    }\n\n}\n\nexport default Diff;","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/Diff.mjs#L99-L135","documentation":"Thrown by Diff run() in the default branch of the diffBy switch, when the 'Diff by' option is not one of Character/Word/Line/Sentence/CSS/JSON. The args are constrained by an option list, so through the UI this is effectively unreachable; it only fires on programmatic invocation with an unlisted diffBy string or an imported recipe whose option value was renamed/removed.","triggerScenarios":"Calling run() with diffBy set to a string outside the supported set - e.g. 'Json' (wrong case), 'Lines' (plural), 'word' (lowercase), or a value from an older recipe format.","commonSituations":"Programmatic/Node-API call with a mistyped diff method; a recipe exported from a different version where the option label differs; a hand-built recipe file with an invalid diffBy enum.","solutions":["Use an exact value from the option list: 'Character', 'Word', 'Line', 'Sentence', 'CSS', or 'JSON' (case-sensitive).","Regenerate or re-export the recipe in the current build.","Validate diffBy against the allowed set before invoking run() programmatically."],"exampleFix":"// before\nop.run(input, [delim, \"word\", ...]); // wrong case\n\n// after\nop.run(input, [delim, \"Word\", ...]);","handlingStrategy":"validation","validationCode":"const DIFF_BY = new Set([\"Character\", \"Word\", \"Line\", \"Sentence\", \"CSS\", \"JSON\"]);\nfunction isValidDiffBy(v) { return DIFF_BY.has(v); }","typeGuard":"/** @returns {boolean} */\nfunction isValidDiffBy(v) {\n    return [\"Character\", \"Word\", \"Line\", \"Sentence\", \"CSS\", \"JSON\"].includes(v);\n}","tryCatchPattern":"try {\n    out = diff.run(input, args);\n} catch (e) {\n    if (e instanceof OperationError && /Invalid 'Diff by' option/.test(e.message)) {\n        args[1] = \"Line\"; // safe default\n        out = diff.run(input, args);\n    } else throw e;\n}","preventionTips":["Use exact diffBy values from the option list (case-sensitive).","Validate diffBy against the allowed set when invoking programmatically.","Regenerate recipes in the current build to keep option labels aligned.","Default to 'Line' when the desired method is unclear."],"tags":["text","diff","validation","programmatic"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}