{"record":{"id":"c75cacb65c2b5144","repo":"n8n-io/n8n","slug":"nodes-json-not-found-at-nodesjsonpath","errorCode":null,"errorMessage":"nodes.json not found at ${nodesJsonPath}","messagePattern":"nodes\\.json not found at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/generate-types/generate-node-defs-cli.ts","lineNumber":65,"sourceCode":"\t\tconst pkg = JSON.parse(fs.readFileSync(sdkPackageJsonPath, 'utf-8')) as { version: string };\n\t\treturn pkg.version;\n\t} catch {\n\t\treturn 'unknown';\n\t}\n}\n\n/**\n * Generate node definitions from a nodes.json file.\n * Skips generation if the input hash matches the stored sentinel.\n * Testable core logic extracted from CLI entry point.\n */\nexport async function generateNodeDefinitions(\n\toptions: GenerateNodeDefinitionsOptions,\n): Promise<void> {\n\tconst { nodesJsonPath, outputDir, packageName } = options;\n\n\tif (!fs.existsSync(nodesJsonPath)) {\n\t\tthrow new Error(`nodes.json not found at ${nodesJsonPath}`);\n\t}\n\n\tconst content = await fs.promises.readFile(nodesJsonPath, 'utf-8');\n\n\t// Hash-based skip: check if output is already up to date\n\tconst sdkVersion = getSdkVersion();\n\tconst inputHash = computeInputHash(content, sdkVersion);\n\tconst hashFilePath = path.join(outputDir, HASH_SENTINEL_FILE);\n\n\ttry {\n\t\tconst existingHash = await fs.promises.readFile(hashFilePath, 'utf-8');\n\t\tif (existingHash.trim() === inputHash) {\n\t\t\tconsole.log('Node definitions up to date (hash match), skipping generation.');\n\t\t\treturn;\n\t\t}\n\t} catch {\n\t\t// Hash file doesn't exist — proceed with generation\n\t}","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/generate-types/generate-node-defs-cli.ts#L47-L83","documentation":"generateNodeDefinitions() is the post-build CLI that turns a package's dist/types/nodes.json into node definitions. Its first action is fs.existsSync(nodesJsonPath); if the file is missing it throws immediately with the resolved path so you know exactly what it looked for.","triggerScenarios":"Running n8n-generate-node-defs before the package build has emitted dist/types/nodes.json; running it from the wrong working directory; passing a custom nodesJsonPath option that points nowhere; build failed silently so nodes.json was never written.","commonSituations":"Fresh checkout where build was skipped; CI running the generate step out of order; custom packaging scripts that override nodesJsonPath; monorepo where the CLI is invoked from the repo root instead of the package dir.","solutions":["Run the package build first (e.g. pnpm build for the node package) so dist/types/nodes.json exists.","Invoke the CLI from the package root, or pass an explicit absolute nodesJsonPath.","Check the printed path with ls to confirm where nodes.json actually is and adjust the option."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import * as fs from 'fs';\nif (!fs.existsSync(nodesJsonPath)) {\n  throw new Error(`Build dist/types/nodes.json is missing at ${nodesJsonPath}. Run the package build first.`);\n}\nawait generateNodeDefinitions({ nodesJsonPath, outputDir, packageName });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run the package build before invoking n8n-generate-node-defs.","Invoke the CLI from the package root, or pass an absolute nodesJsonPath.","In CI, assert dist/types/nodes.json exists immediately after the build step."],"tags":["build","cli","config","filesystem"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}