{"record":{"id":"51a31aa426ca68a2","repo":"nanocoai/nanoclaw","slug":"nanoclaw-extension-ns-context-instructions-md-m","errorCode":null,"errorMessage":"${NANOCLAW_EXTENSION_NS}/context/instructions.md must be a regular file","messagePattern":"(.+?)/context/instructions\\.md must be a regular file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/templates/extension.ts","lineNumber":70,"sourceCode":"          report.push(\n            `plugin.json: extensions[\"${NANOCLAW_EXTENSION_NS}\"].agentName must be a nonempty string; ignored`,\n          );\n      }\n      for (const key of Object.keys(ours)) {\n        if (key !== 'agentName') {\n          report.push(`plugin.json: extensions[\"${NANOCLAW_EXTENSION_NS}\"].${key} is not recognized; ignored`);\n        }\n      }\n    }\n  }\n\n  const extDir = path.join(pluginDir, NANOCLAW_EXTENSION_NS);\n  const contextDir = path.join(extDir, 'context');\n  const instructionsFile = path.join(contextDir, 'instructions.md');\n  let instructions: string | undefined;\n  if (fs.existsSync(instructionsFile)) {\n    if (!fs.lstatSync(instructionsFile).isFile()) {\n      throw new Error(`${NANOCLAW_EXTENSION_NS}/context/instructions.md must be a regular file`);\n    }\n    instructions = fs.readFileSync(instructionsFile, 'utf-8').trimEnd();\n  }\n\n  return {\n    ...(agentName === undefined ? {} : { agentName }),\n    ...(instructions === undefined ? {} : { instructions }),\n    contextExtras: readContextExtras(contextDir),\n    tasks: readTasks(path.join(extDir, 'tasks'), `${NANOCLAW_EXTENSION_NS}/tasks`),\n    report,\n  };\n}\n\n/**\n * Every context/**\\/*.md except the top-level instructions.md, recursively.\n * `name` keeps the path relative to context/ so stamping can preserve the\n * layout — a reference like `additional_context/faq.md` written in\n * instructions.md resolves unchanged in the agent's workspace.","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/templates/extension.ts#L52-L88","documentation":"When reading a NanoClaw plugin/template extension, the loader expects <extension-ns>/context/instructions.md to be a regular file. It exists (fs.existsSync passes) but lstatSync().isFile() is false — meaning it is a symlink, directory, FIFO, or other special file — so the extension is rejected as malformed.","triggerScenarios":"instructions.md being a symlink (e.g. dotfiles-managed config, ln -s into a repo), a directory accidentally created at that path, or a broken symlink that happens to satisfy existsSync via a target somewhere.","commonSituations":"Users managing templates with GNU stow or symlinking a shared instructions file across templates; a mistaken 'mkdir instructions.md'; package managers that materialize symlinks.","solutions":["Replace the symlink with a real file: cp -L symlink temp && mv temp instructions.md (or remove dotfile stowing for this path).","If it is a directory, remove it and create a regular file with the instruction text.","If sharing content across templates is the goal, duplicate the file or generate it at build time instead of symlinking."],"exampleFix":"# before\ncontext/instructions.md -> ../../shared-instructions.md  (symlink)\n\n# after\ncp -L ../../shared-instructions.md context/instructions.md","handlingStrategy":"validation","validationCode":"import * as fs from 'node:fs';\nconst p = path.join(extDir, 'context', 'instructions.md');\nif (fs.existsSync(p) && !fs.statSync(p).isFile()) throw new Error('instructions.md is not a regular file — fix the template layout');","typeGuard":"const isRegularFile = (p: string): boolean => { try { return fs.lstatSync(p).isFile(); } catch { return false; } };","tryCatchPattern":"try { ext = readNanoclawExtension(pluginDir); } catch (err) { if ((err as Error).message.includes('must be a regular file')) throw new Error('Template instructions.md is a symlink/dir — replace with a real file', { cause: err }); throw err; }","preventionTips":["Don't symlink template files; copy or generate them.","Run a template lint (stat each expected file) in CI."],"tags":["templates","filesystem","symlink"],"backgroundTag":"path-is-not-a-regular-file","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}