{"record":{"id":"95d883224cbad418","repo":"n8n-io/n8n","slug":"expr-requires-a-string-argument-but-received","errorCode":null,"errorMessage":"expr() requires a string argument, but received ${typeof value}.","messagePattern":"expr\\(\\) requires a string argument, but received (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/expression/index.ts","lineNumber":61,"sourceCode":"\t\t'__newCredential' in value &&\n\t\t(value as Record<string, unknown>).__newCredential === true &&\n\t\t'name' in value &&\n\t\ttypeof (value as Record<string, unknown>).name === 'string'\n\t);\n}\n\nexport function expr(expression: string): string {\n\tif (typeof expression !== 'string') {\n\t\t// At runtime, the AST interpreter may pass non-string values (e.g. NewCredentialImpl objects).\n\t\t// TypeScript narrows to `never` here since the param is typed as `string`,\n\t\t// so we re-bind as `unknown` to perform runtime type checks.\n\t\tconst value: unknown = expression;\n\t\tif (isNewCredentialLike(value)) {\n\t\t\tthrow new Error(\n\t\t\t\t`expr(newCredential('${value.name}')) is invalid. Use newCredential() directly in the credentials config, not inside expr().`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(`expr() requires a string argument, but received ${typeof value}.`);\n\t}\n\t// Strip any leading '=' to prevent double-equals patterns from LLM output\n\tconst normalized = expression.startsWith('=') ? expression.slice(1) : expression;\n\treturn '=' + normalized;\n}\n\n// =============================================================================\n// Explicit Node JSON Reference Generator\n// =============================================================================\n\ntype NodeJsonReference = NodeInstance<string, string, unknown> | string;\n\nconst IDENTIFIER_PATH_SEGMENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\nfunction resolveNodeName(node: NodeJsonReference): string {\n\treturn typeof node === 'string' ? node : node.name;\n}\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/expression/index.ts#L43-L79","documentation":"expr() requires a string argument. If the value passed is neither a string nor a NewCredentialImpl-like object, this generic error reports the actual typeof it received. It exists because the AST interpreter does not enforce the TypeScript string annotation at runtime.","triggerScenarios":"Calling expr(123), expr(someObject), expr(undefined), expr($json.count) where $json.count is a number, or expr(true). Also expr() with no argument.","commonSituations":"Passing numeric/boolean/object workflow data into expr(); LLM forgetting to interpolate a value into a string; referencing a field whose runtime type is not string.","solutions":["Coerce the value to a string before calling expr(), e.g. expr(`${$json.count}`) or expr(String(value)).","Confirm the upstream field is actually a string; if it can be undefined, default it first.","Use expr() only for literal expression text containing {{ }} syntax, not for arbitrary data."],"exampleFix":"// before\nconst url = expr($json.baseUrl);   // $json.baseUrl may be undefined/non-string\n// after\nconst url = expr(`={{ $json.baseUrl }}`);  // pass a literal expression string","handlingStrategy":"type-guard","validationCode":"// Coerce or reject non-strings before expr().\nfunction asExprString(v: unknown): string {\n  if (typeof v !== 'string') throw new TypeError(`expr() needs a string, got ${typeof v}`);\n  return v;\n}\nconst out = expr(asExprString(maybeValue));","typeGuard":"function isString(v: unknown): v is string { return typeof v === 'string'; }","tryCatchPattern":null,"preventionTips":["Only pass literal expression strings (with {{ }}) to expr().","Coerce numbers/booleans with String() or template literals before expr().","Default potentially-undefined fields before passing them in."],"tags":["expression","type-validation","runtime","sdk"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}