paperclipai/paperclip · error · Error
template path must be one of ${TEMPLATE_FILES.join(", ")}
Error message
template path must be one of ${TEMPLATE_FILES.join(", ")} What it means
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.
Source
Thrown at packages/plugins/plugin-llm-wiki/src/wiki/core.ts:4451
);
const row = meta[0] ?? null;
return {
wikiId,
spaceSlug: space.slug,
path,
contents,
title: row?.title ?? inferTitle(path, contents),
pageType: row?.page_type ?? inferPageType(path),
backlinks: Array.isArray(row?.backlinks) ? row?.backlinks : [],
sourceRefs: Array.isArray(row?.source_refs) ? row?.source_refs : [],
updatedAt: row?.updated_at ?? null,
hash: contentHash(contents),
};
}
export async function readTemplate(ctx: PluginContext, input: { companyId: string; path: string }) {
if (!isTemplateFile(input.path)) {
throw new Error(`template path must be one of ${TEMPLATE_FILES.join(", ")}`);
}
try {
const contents = await ctx.localFolders.readText(input.companyId, WIKI_ROOT_FOLDER_KEY, input.path);
return { path: input.path, contents, hash: contentHash(contents), exists: true };
} catch (error) {
return { path: input.path, contents: "", hash: null, exists: false, error: error instanceof Error ? error.message : String(error) };
}
}
export async function writeTemplate(ctx: PluginContext, input: { companyId: string; path: string; contents: string }) {
if (!isTemplateFile(input.path)) {
throw new Error(`template path must be one of ${TEMPLATE_FILES.join(", ")}`);
}
await ctx.localFolders.writeTextAtomic(input.companyId, WIKI_ROOT_FOLDER_KEY, input.path, input.contents);
return { status: "ok", path: input.path, hash: contentHash(input.contents) };
}
export type DistillationCursorRow = {View on GitHub (pinned to 67001ec6eb)
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.
Example fix
// before
readTemplate(ctx, { companyId, path: 'agents.md' });
// after
readTemplate(ctx, { companyId, path: 'AGENTS.md' }); Defensive patterns
Strategy: type-guard
Validate before calling
const TEMPLATE_FILES = ['AGENTS.md', 'IDEA.md'] as const;
function assertTemplatePath(path: string) {
if (!TEMPLATE_FILES.includes(path as any)) throw new Error(`path must be one of ${TEMPLATE_FILES.join(', ')}`);
} Type guard
const TEMPLATE_FILES = ['AGENTS.md', 'IDEA.md'] as const;
type WikiTemplateFile = typeof TEMPLATE_FILES[number];
function isTemplateFile(path: string): path is WikiTemplateFile {
return (TEMPLATE_FILES as readonly string[]).includes(path);
} Prevention
- Restrict UI inputs to a dropdown of TEMPLATE_FILES.
- Use readWikiPage for non-template files.
When it happens
Trigger: Calling readTemplate with a path other than 'AGENTS.md' or 'IDEA.md' (e.g. 'agents.md' lowercase, 'README.md', a directory path).
Common situations: 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.
Related errors
- selected_projects exceeds the hard cap of ${MAX_PAPERCLIP_PR
- Project belongs to another company or does not exist: ${proj
- root_issues exceeds the hard cap of ${MAX_PAPERCLIP_PROFILE_
- Issue belongs to another company or does not exist: ${issueI
- Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: $
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/bd399fc3893beaca.
Report an issue: GitHub.