{"record":{"id":"bd399fc3893beaca","repo":"paperclipai/paperclip","slug":"template-path-must-be-one-of-template-files-join","errorCode":null,"errorMessage":"template path must be one of ${TEMPLATE_FILES.join(\", \")}","messagePattern":"template path must be one of (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/plugin-llm-wiki/src/wiki/core.ts","lineNumber":4451,"sourceCode":"  );\n  const row = meta[0] ?? null;\n  return {\n    wikiId,\n    spaceSlug: space.slug,\n    path,\n    contents,\n    title: row?.title ?? inferTitle(path, contents),\n    pageType: row?.page_type ?? inferPageType(path),\n    backlinks: Array.isArray(row?.backlinks) ? row?.backlinks : [],\n    sourceRefs: Array.isArray(row?.source_refs) ? row?.source_refs : [],\n    updatedAt: row?.updated_at ?? null,\n    hash: contentHash(contents),\n  };\n}\n\nexport async function readTemplate(ctx: PluginContext, input: { companyId: string; path: string }) {\n  if (!isTemplateFile(input.path)) {\n    throw new Error(`template path must be one of ${TEMPLATE_FILES.join(\", \")}`);\n  }\n  try {\n    const contents = await ctx.localFolders.readText(input.companyId, WIKI_ROOT_FOLDER_KEY, input.path);\n    return { path: input.path, contents, hash: contentHash(contents), exists: true };\n  } catch (error) {\n    return { path: input.path, contents: \"\", hash: null, exists: false, error: error instanceof Error ? error.message : String(error) };\n  }\n}\n\nexport async function writeTemplate(ctx: PluginContext, input: { companyId: string; path: string; contents: string }) {\n  if (!isTemplateFile(input.path)) {\n    throw new Error(`template path must be one of ${TEMPLATE_FILES.join(\", \")}`);\n  }\n  await ctx.localFolders.writeTextAtomic(input.companyId, WIKI_ROOT_FOLDER_KEY, input.path, input.contents);\n  return { status: \"ok\", path: input.path, hash: contentHash(input.contents) };\n}\n\nexport type DistillationCursorRow = {","sourceCodeStart":4433,"sourceCodeEnd":4469,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/plugin-llm-wiki/src/wiki/core.ts#L4433-L4469","documentation":"Thrown by readTemplate when input.path is not in TEMPLATE_FILES (['AGENTS.md','IDEA.md']). Templates are an enumerated set, not arbitrary files; the guard prevents reading non-template files from the WIKI_ROOT_FOLDER. It runs before the filesystem read.","triggerScenarios":"Calling readTemplate with a path other than 'AGENTS.md' or 'IDEA.md' (e.g. 'agents.md' lowercase, 'README.md', a directory path).","commonSituations":"Case mismatch (the check is case-sensitive via isTemplateFile); copying a path from a wiki page that is not a template; passing a user-supplied path without validation.","solutions":["Use exactly 'AGENTS.md' or 'IDEA.md' (case-sensitive).","If you need to read a non-template wiki file, use readWikiPage instead.","Validate the path against the TEMPLATE_FILES list at the caller before invoking readTemplate."],"exampleFix":"// before\nreadTemplate(ctx, { companyId, path: 'agents.md' });\n// after\nreadTemplate(ctx, { companyId, path: 'AGENTS.md' });","handlingStrategy":"type-guard","validationCode":"const TEMPLATE_FILES = ['AGENTS.md', 'IDEA.md'] as const;\nfunction assertTemplatePath(path: string) {\n  if (!TEMPLATE_FILES.includes(path as any)) throw new Error(`path must be one of ${TEMPLATE_FILES.join(', ')}`);\n}","typeGuard":"const TEMPLATE_FILES = ['AGENTS.md', 'IDEA.md'] as const;\ntype WikiTemplateFile = typeof TEMPLATE_FILES[number];\nfunction isTemplateFile(path: string): path is WikiTemplateFile {\n  return (TEMPLATE_FILES as readonly string[]).includes(path);\n}","tryCatchPattern":null,"preventionTips":["Restrict UI inputs to a dropdown of TEMPLATE_FILES.","Use readWikiPage for non-template files."],"tags":["paperclip","wiki","template","validation"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}