{"record":{"id":"51735f7f6922eb34","repo":"gchq/CyberChef","slug":"this-name-must-be-one-of-the-following-permi","errorCode":null,"errorMessage":"${this.name} must be one of the following: ${permittedOptions.join(\", \")}.","messagePattern":"(.+?) must be one of the following: (.+?)\\.","errorType":"validation","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/Ingredient.mjs","lineNumber":153,"sourceCode":"            if (typeof this.min === \"number\" && checkVal < this.min) {\n                throw new OperationError(`${this.name} must be greater than or equal to ${this.min}.`);\n            }\n            if (typeof this.max === \"number\" && checkVal > this.max) {\n                throw new OperationError(`${this.name} must be less than or equal to ${this.max}.`);\n            }\n        }\n\n        // 4. option checks\n        if (this.type === \"option\") {\n            if (Array.isArray(this.defaultValue)) {\n                const permittedOptions = this.defaultValue.filter(opt => {\n                    if (typeof opt !== \"string\") return false;\n                    return !opt.match(/^\\[\\/?[a-z0-9 -()^]+\\]$/i);\n                });\n                const valStr = (checkVal !== null && checkVal !== undefined) ? String(checkVal).toLowerCase() : \"\";\n                const matchedOption = permittedOptions.find(opt => opt.toLowerCase() === valStr);\n                if (!matchedOption) {\n                    throw new OperationError(`${this.name} must be one of the following: ${permittedOptions.join(\", \")}.`);\n                }\n            }\n        }\n\n        // 5. argSelector checks\n        if (this.type === \"argSelector\") {\n            if (Array.isArray(this.defaultValue)) {\n                const permittedOptions = this.defaultValue\n                    .map(opt => opt.name)\n                    .filter(optName => {\n                        if (typeof optName !== \"string\") return false;\n                        return !optName.match(/^\\[\\/?[a-z0-9 -()^]+\\]$/i);\n                    });\n                const valStr = (checkVal !== null && checkVal !== undefined) ? String(checkVal).toLowerCase() : \"\";\n                const matchedOption = permittedOptions.find(opt => opt.toLowerCase() === valStr);\n                if (!matchedOption) {\n                    throw new OperationError(`${this.name} must be one of the following: ${permittedOptions.join(\", \")}.`);\n                }","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/Ingredient.mjs#L135-L171","documentation":"Thrown by Ingredient.validate() option checks (line 153) when type is 'option', defaultValue is an Array, and after lowercasing, checkVal matches none of the permitted options. Permitted options are defaultValue entries that are strings AND do not match the placeholder regex /^[/?[a-z0-9 -()^]+]$/i (bracketed placeholders like [Alpha] are excluded). Matching is case-insensitive.","triggerScenarios":"An option ingredient (dropdown) receives a value that is not one of its declared options; e.g. a 'Mode' option with permitted ['CBC','ECB'] gets 'CFB'; or the only entries are bracketed placeholders so permittedOptions is empty and nothing matches.","commonSituations":"Recipe references an option value renamed or removed in a newer operation version; typo in the option value; locale/case mismatch; copying an option arg from a different operation.","solutions":["Set the ingredient to one of the values listed in the error message (case-insensitive).","If the operation's options changed, update the recipe to a currently-valid option.","Confirm defaultValue in the operation config actually lists real options, not only bracketed placeholders."],"exampleFix":"// before - permitted: CBC, ECB\nop.ingValues = ['CFB'];\n\n// after\nop.ingValues = ['CBC'];","handlingStrategy":"validation","validationCode":"const permitted = defaultValue.filter(o => typeof o === 'string' && !/^[/?[a-z0-9 -()^]+]$/i.test(o));\nif (!permitted.some(o => o.toLowerCase() === String(val).toLowerCase())) {\n  throw new Error(`${name} not in ${permitted.join(', ')}`);\n}","typeGuard":"function isValidOption(v, permitted): v is string { return typeof v === 'string' && permitted.some(o => o.toLowerCase() === v.toLowerCase()); }","tryCatchPattern":"try { op.ingValues = [val]; } catch (e) { if (/must be one of the following/.test(e.message)) { val = permitted[0]; } }","preventionTips":["Pull option lists from the current operation version, not a cached recipe.","Use exact option strings; matching is case-insensitive but spelling must match.","Avoid recipes that reference removed/renamed options."],"tags":["ingredient","validation","option","dropdown","operationerror"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}