{"record":{"id":"a25d80ba1e63b570","repo":"n8n-io/n8n","slug":"could-not-read-node-catalogue-at-jsonpath-me","errorCode":null,"errorMessage":"Could not read node catalogue at ${jsonPath}: ${message}\nRun `pnpm export:nodes` in packages/@n8n/ai-workflow-builder.ee to generate it, or pass --nodes-json <path> to point at an existing file.","messagePattern":"Could not read node catalogue at (.+?): (.+?)\nRun `pnpm export:nodes` in packages/@n8n/ai-workflow-builder\\.ee to generate it, or pass --nodes-json <path> to point at an existing file\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/instance-ai/evaluations/harness/stub-services.ts","lineNumber":341,"sourceCode":"}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface NodeCatalogue {\n\tsearchableNodes: SearchableNodeDescription[];\n\t/** Indexed by node `name` for O(1) `getDescription` lookups. */\n\tdescriptionsByName: Map<string, NodeDescription>;\n}\n\nasync function loadNodeCatalogue(jsonPath: string): Promise<NodeCatalogue> {\n\tlet content: string;\n\ttry {\n\t\tcontent = await fs.readFile(jsonPath, 'utf8');\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`Could not read node catalogue at ${jsonPath}: ${message}\\n` +\n\t\t\t\t'Run `pnpm export:nodes` in packages/@n8n/ai-workflow-builder.ee to generate it, ' +\n\t\t\t\t'or pass --nodes-json <path> to point at an existing file.',\n\t\t);\n\t}\n\n\tconst parsed = jsonParse<unknown>(content, {\n\t\terrorMessage: `Could not parse node catalogue at ${jsonPath} as JSON`,\n\t});\n\tif (!Array.isArray(parsed)) {\n\t\tthrow new Error(`Expected ${jsonPath} to contain a JSON array of node descriptions.`);\n\t}\n\n\tconst searchableNodes: SearchableNodeDescription[] = [];\n\tconst descriptionsByName = new Map<string, NodeDescription>();\n\tfor (const entry of parsed) {\n\t\tconst searchable = coerceSearchableNode(entry);\n\t\tsearchableNodes.push(searchable);","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/evaluations/harness/stub-services.ts#L323-L359","documentation":"Thrown by loadNodeCatalogue when readFile fails on the catalogue JSON path. The error wraps the underlying filesystem message and tells the operator exactly how to regenerate the file (pnpm export:nodes) or point at an existing one via --nodes-json. It does not fire for malformed-but-readable JSON — that is a separate error.","triggerScenarios":"The catalogue path does not exist (most common — first run, or after a clean checkout); the path is a directory or lacks read permissions; the --nodes-json flag was not passed and the default location is empty.","commonSituations":"First eval run on a fresh clone without running export:nodes; CI job that skips the catalogue-generation step; relative path resolved against the wrong cwd.","solutions":["Run `pnpm export:nodes` in packages/@n8n/ai-workflow-builder.ee to generate the catalogue at the expected location.","If a catalogue exists elsewhere, pass `--nodes-json <path>` to the harness to point at it.","Read the embedded underlying message to distinguish ENOENT (missing) from EACCES (permissions)."],"exampleFix":"# before — run evals without generating the catalogue\npnpm eval\n\n# after — generate first, then run\ncd packages/@n8n/ai-workflow-builder.ee && pnpm export:nodes && cd -\npnpm eval\n# or: pnpm eval --nodes-json /path/to/existing/nodes.json","handlingStrategy":"validation","validationCode":"import { existsSync, statSync } from 'node:fs';\n\nfunction catalogueReadable(path: string): boolean {\n  try {\n    return existsSync(path) && statSync(path).isFile();\n  } catch {\n    return false;\n  }\n}\n\nif (!catalogueReadable(path)) {\n  throw new Error(`node catalogue missing at ${path}; run pnpm export:nodes or pass --nodes-json`);\n}","typeGuard":"function isNodeCatalogueReadError(e: unknown): boolean {\n  return e instanceof Error && e.message.startsWith('Could not read node catalogue at ');\n}","tryCatchPattern":"try {\n  await loadNodeCatalogue(path);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Could not read node catalogue')) {\n    // run `pnpm export:nodes` or pass --nodes-json, then retry\n  }\n  throw e;\n}","preventionTips":["Generate the catalogue in CI before running evals.","Commit it or fetch from artefact storage.","Default --nodes-json to a known-good path in dev scripts."],"tags":["eval-harness","stub-services","node-catalogue","filesystem","configuration"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}