{"record":{"id":"d6e5b72715efd77a","repo":"n8n-io/n8n","slug":"nodejson-requires-a-non-empty-json-path","errorCode":null,"errorMessage":"nodeJson() requires a non-empty JSON path.","messagePattern":"nodeJson\\(\\) requires a non-empty JSON path\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/expression/index.ts","lineNumber":89,"sourceCode":"\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\nfunction escapeNodeName(nodeName: string): string {\n\treturn nodeName.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction normalizePath(path: string | readonly string[]): string[] {\n\tconst segments = typeof path === 'string' ? path.split('.') : [...path];\n\tconst normalized = segments.map((segment) => segment.trim());\n\n\tif (normalized.length === 0 || normalized.some((segment) => segment.length === 0)) {\n\t\tthrow new Error('nodeJson() requires a non-empty JSON path.');\n\t}\n\n\treturn normalized;\n}\n\nfunction formatPathSegment(segment: string): string {\n\tif (IDENTIFIER_PATH_SEGMENT.test(segment)) {\n\t\treturn `.${segment}`;\n\t}\n\n\treturn `[${JSON.stringify(segment)}]`;\n}\n\n/**\n * Build an expression that references JSON data from a specific node by name.\n *\n * Prefer this over `$json` when a value comes from an AI subnode, a fan-in\n * branch, or any node other than the immediate main-flow predecessor.","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/expression/index.ts#L71-L107","documentation":"nodeJson() builds a {{ $('Node').item.json.<path> }} reference. normalizePath() splits the path on '.' (or accepts an array) and rejects the result if there are zero segments or any empty segment after trimming. This guards against malformed dotted paths that would produce invalid expression syntax.","triggerScenarios":"nodeJson(node, ''), nodeJson(node, '.'), nodeJson(node, 'a.'), nodeJson(node, '.a'), nodeJson(node, 'a..b'), nodeJson(node, ['','b']), nodeJson(node, []), or nodeJson(node, '   ').","commonSituations":"Path is built dynamically from missing/empty data; LLM passes an empty path; user copies a partial path; trailing dot typo.","solutions":["Provide a concrete non-empty dotted path like 'message.chat.id' or a non-empty array of segments.","If the path is dynamic, validate each segment is non-empty before calling nodeJson().","Trim and check the path string before passing it."],"exampleFix":"// before\nconst ref = nodeJson('Set User', '');\n// after\nconst ref = nodeJson('Set User', 'profile.email');","handlingStrategy":"validation","validationCode":"// Validate the path before calling nodeJson().\nfunction validPath(p: string | readonly string[]): boolean {\n  const segs = (typeof p === 'string' ? p.split('.') : [...p]).map((s) => s.trim());\n  return segs.length > 0 && segs.every((s) => s.length > 0);\n}\nif (!validPath(path)) throw new Error('path must be non-empty with no blank segments');\nconst ref = nodeJson(node, path);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass a concrete dotted path like 'message.chat.id'.","If the path is dynamic, validate each segment is non-empty after trimming.","Avoid leading/trailing/double dots in dotted strings."],"tags":["expression","validation","sdk","runtime"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}