{"record":{"id":"eb57884b2931439c","repo":"gchq/CyberChef","slug":"inputted-function-not-a-chef-operation","errorCode":null,"errorMessage":"Inputted function not a Chef operation.","messagePattern":"Inputted function not a Chef operation\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/node/NodeRecipe.mjs","lineNumber":54,"sourceCode":"            const op = operations.find((op) => {\n                return sanitise(op.opName) === sanitise(ing);\n            });\n            if (op) {\n                // Need to validate against case 2\n                return this._validateIngredient(op);\n            } else {\n                throw new TypeError(`Couldn't find an operation with name '${ing}'.`);\n            }\n        // CASE operation given. Check its a chef operation and check its not flowcontrol\n        } else if (typeof ing === \"function\") {\n            if (ing.flowControl) {\n                throw new TypeError(`flowControl operations like ${ing.opName} are not currently allowed in recipes for chef.bake in the Node API`);\n            }\n\n            if (operations.includes(ing)) {\n                return ing;\n            } else {\n                throw new TypeError(\"Inputted function not a Chef operation.\");\n            }\n        // CASE: op, maybe with configuration\n        } else if (ing.op) {\n            const sanitisedOp = this._validateIngredient(ing.op);\n            if (ing.args) {\n                return {op: sanitisedOp, args: ing.args};\n            }\n            return sanitisedOp;\n        } else {\n            throw new TypeError(\"Recipe can only contain function names or functions\");\n        }\n    }\n\n\n    /**\n     * Parse an opList from a recipeConfig and assign it to the recipe's opList.\n     * @param {String | Function | String[] | Function[] | [String | Function]} recipeConfig\n     */","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/node/NodeRecipe.mjs#L36-L72","documentation":"Thrown by NodeRecipe._validateIngredient when the ingredient is a function that is not flowControl but is not present in the registered operations list. It distinguishes 'wrong kind of function' from 'unknown name' (714) and 'flowControl' (715).","triggerScenarios":"A plain JS function, or an operation class from a different CyberChef build/fork, is passed in the recipe array. operations.includes(ing) is a reference check, so an operation imported from a mismatched version is a different object and fails the includes test.","commonSituations":"Importing an operation class from source while the Node API bundled its own copy (two module instances); passing a custom function thinking it will be invoked; mixing built recipe JSON with freshly imported classes.","solutions":["Pass operations by their canonical string name (handled by case 714's lookup) rather than as function references.","Ensure the operation you import is the same module instance the Node API uses (same node_modules/CyberChef).","Don't put arbitrary functions in a Node recipe — the API only accepts Chef operations or their names."],"exampleFix":"// before: imported op is a different instance than the API's\nimport {FromHex} from \"cyberchef/src/...\";\nchef.bake(input, [FromHex]);\n// after: reference by name\nchef.bake(input, [\"From Hex\"]);","handlingStrategy":"type-guard","validationCode":"import { operations } from \"cyberchef/src/node/index.mjs\";\nfunction assertOpsRegistered(recipe) {\n  for (const ing of recipe) if (typeof ing === \"function\" && !ing.flowControl && !operations.includes(ing))\n    throw new Error(\"Function is not a registered Chef operation; pass by name instead.\");\n}","typeGuard":"const isChefOperation = (ing) => typeof ing === \"function\" && operations.includes(ing);","tryCatchPattern":"try { chef.bake(input, recipe); } catch (e) { if (e instanceof TypeError && /not a Chef operation/.test(e.message)) { /* pass op by name string */ } else throw e; }","preventionTips":["Reference operations by canonical name string in Node recipes.","Avoid importing operation classes from a second CyberChef module instance.","Don't place arbitrary functions in recipes."],"tags":["node-api","noderecipe","invalid-operation","module-instance"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}