{"record":{"id":"26ef4267db3fe62e","repo":"gchq/CyberChef","slug":"recipe-can-only-contain-function-names-or-function","errorCode":null,"errorMessage":"Recipe can only contain function names or functions","messagePattern":"Recipe can only contain function names or functions","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/node/NodeRecipe.mjs","lineNumber":64,"sourceCode":"        } 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     */\n    _parseConfig(recipeConfig) {\n        if (!recipeConfig) {\n            this.opList = [];\n            return;\n        }\n\n        if (!Array.isArray(recipeConfig)) {\n            recipeConfig = [recipeConfig];\n        }\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/node/NodeRecipe.mjs#L46-L82","documentation":"Thrown by NodeRecipe._validateIngredient as the final fallback when the ingredient is neither a string (op name), nor a function (operation class), nor an object with an 'op' property. It is the catch-all for structurally invalid recipe entries.","triggerScenarios":"A recipe array contains a number, boolean, null, array, or an object without an 'op' key. Example: [{operation: \"From Hex\"}] (wrong key — must be 'op') or [42].","commonSituations":"Wrong recipe schema (using 'operation'/'name' instead of 'op'); passing a nested array; nulls from optional-chaining bugs when building the recipe dynamically.","solutions":["Use one of the supported shapes: an operation name string, an operation function, or {op: \"<name>\", args: [...]} with the 'op' key (not 'operation'/'name').","Remove null/undefined/empty entries before building the recipe.","Validate each entry's shape before passing the array to chef.bake."],"exampleFix":"// before: wrong key\nchef.bake(input, [{operation:\"From Hex\", args:[\"None\"]}]);\n// after\nchef.bake(input, [{op:\"From Hex\", args:[\"None\"]}]);","handlingStrategy":"type-guard","validationCode":"function isValidIngredient(ing) {\n  return typeof ing === \"string\" || typeof ing === \"function\" || (ing && typeof ing === \"object\" && \"op\" in ing);\n}\nfunction assertRecipeShape(recipe) {\n  for (const ing of recipe) if (!isValidIngredient(ing)) throw new Error(\"Recipe entry must be a name, function, or {op, args?}\");\n}","typeGuard":"const isRecipeEntry = (ing) => typeof ing === \"string\" || typeof ing === \"function\" || (ing != null && typeof ing === \"object\" && Object.prototype.hasOwnProperty.call(ing, \"op\"));","tryCatchPattern":"try { chef.bake(input, recipe); } catch (e) { if (e instanceof TypeError && /only contain function names or functions/.test(e.message)) { /* fix entry shape to {op, args?} */ } else throw e; }","preventionTips":["Use only supported shapes: string | function | {op, args?} (key is 'op', not 'operation'/'name').","Filter out null/undefined/array entries when building recipes dynamically.","Validate the schema before calling chef.bake."],"tags":["node-api","noderecipe","recipe-schema","type-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}