{"record":{"id":"01bcc181a3f71149","repo":"paperclipai/paperclip","slug":"wiki-page-writes-must-target-agents-md-idea-md-o","errorCode":null,"errorMessage":"Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: ${path}","messagePattern":"Wiki page writes must target AGENTS\\.md, IDEA\\.md, or wiki/: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/plugin-llm-wiki/src/wiki/core.ts","lineNumber":1185,"sourceCode":"    trimmed !== \".gitignore\" &&\n    trimmed !== \"WIKI.md\" &&\n    trimmed !== \"AGENTS.md\" &&\n    trimmed !== \"IDEA.md\" &&\n    trimmed !== \"index.md\" &&\n    trimmed !== \"log.md\" &&\n    !trimmed.startsWith(\"raw/\") &&\n    !trimmed.startsWith(\"wiki/\") &&\n    !(options.allowMetadata && trimmed.startsWith(\".paperclip/\"))\n  ) {\n    throw new Error(`Wiki path must stay inside AGENTS.md, IDEA.md, raw/, or wiki/: ${path}`);\n  }\n  return trimmed;\n}\n\nfunction assertPagePath(path: string): string {\n  const normalized = assertWikiPath(path);\n  if (normalized !== \"index.md\" && normalized !== \"log.md\" && normalized !== \"WIKI.md\" && normalized !== \"AGENTS.md\" && normalized !== \"IDEA.md\" && !normalized.startsWith(\"wiki/\")) {\n    throw new Error(`Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: ${path}`);\n  }\n  if (!normalized.endsWith(\".md\")) {\n    throw new Error(`Wiki page path must be a markdown file: ${path}`);\n  }\n  return normalized;\n}\n\nfunction assertPageWriteAllowed(path: string, writer: WritePageInput[\"writer\"] = \"agent_tool\"): void {\n  if (writer !== \"board_ui\" && PROTECTED_WIKI_CONTROL_FILES.has(path)) {\n    throw new Error(`Refusing to overwrite protected wiki control file ${path}; board-managed edits must use the wiki UI.`);\n  }\n}\n\nfunction assertRawPath(path: string): string {\n  const normalized = assertWikiPath(path);\n  if (!normalized.startsWith(\"raw/\")) {\n    throw new Error(`Source path must stay inside raw/: ${path}`);\n  }","sourceCodeStart":1167,"sourceCodeEnd":1203,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/plugin-llm-wiki/src/wiki/core.ts#L1167-L1203","documentation":"Thrown by assertPagePath after assertWikiPath succeeds, when the normalized path is not index.md, log.md, WICKI.md, AGENTS.md, IDEA.md, or under wiki/. It restricts markdown page writes to page-eligible locations (raw/ is intentionally excluded).","triggerScenarios":"Calling a page-write API (writePage) with a path under raw/ or with a non-page top-level file like '.gitignore'.","commonSituations":"Using the page API to write a raw asset by mistake; routing a binary or source file through the page writer; misclassifying a raw/ asset as a wiki page.","solutions":["For markdown pages, target wiki/<name>.md or the control files (AGENTS.md, IDEA.md, WIKI.md, index.md, log.md).","For raw assets, use the raw-source write API (assertRawPath) so the path lands under raw/.","Validate the intended path against the page allowlist before calling writePage."],"exampleFix":"// before\nawait writePage(ctx, { companyId, path: \"raw/notes.md\" });\n\n// after\nawait writeRawSource(ctx, { companyId, path: \"raw/notes.md\" });\n// or for a page:\nawait writePage(ctx, { companyId, path: \"wiki/notes.md\" });","handlingStrategy":"validation","validationCode":"const PAGE_ALLOWED = new Set([\"index.md\", \"log.md\", \"WIKI.md\", \"AGENTS.md\", \"IDEA.md\"]);\nfunction sanitizePagePath(path) {\n  const t = String(path).trim().replace(/^\\/+/, \"\");\n  if (!PAGE_ALLOWED.has(t) && !t.startsWith(\"wiki/\")) {\n    throw new Error(`Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: ${path}`);\n  }\n  return t;\n}","typeGuard":"function isPagePath(path) {\n  const t = String(path ?? \"\").trim().replace(/^\\/+/, \"\");\n  return PAGE_ALLOWED.has(t) || t.startsWith(\"wiki/\");\n}","tryCatchPattern":"try {\n  await writePage(ctx, { companyId, path, content });\n} catch (err) {\n  if (/page writes must target/.test(err.message)) {\n    path = path.startsWith(\"raw/\") ? path.replace(/^raw\\//, \"wiki/\") : `wiki/${path}`;\n    return writePage(ctx, { companyId, path, content });\n  }\n  throw err;\n}","preventionTips":["Use wiki/ for page content; use raw/ via the raw-source API for assets.","Do not route non-page files through writePage.","Validate the page allowlist at the boundary."],"tags":["validation","wiki","paths","paperclip"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}