paperclipai/paperclip · error · Error
Source path must stay inside raw/: ${path}
Error message
Source path must stay inside raw/: ${path} What it means
Thrown by assertRawPath when assertWikiPath succeeds but the normalized path does not start with 'raw/'. All raw source assets must live under that prefix so the wiki can separate them from page content.
Source
Thrown at packages/plugins/plugin-llm-wiki/src/wiki/core.ts:1202
if (normalized !== "index.md" && normalized !== "log.md" && normalized !== "WIKI.md" && normalized !== "AGENTS.md" && normalized !== "IDEA.md" && !normalized.startsWith("wiki/")) {
throw new Error(`Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: ${path}`);
}
if (!normalized.endsWith(".md")) {
throw new Error(`Wiki page path must be a markdown file: ${path}`);
}
return normalized;
}
function assertPageWriteAllowed(path: string, writer: WritePageInput["writer"] = "agent_tool"): void {
if (writer !== "board_ui" && PROTECTED_WIKI_CONTROL_FILES.has(path)) {
throw new Error(`Refusing to overwrite protected wiki control file ${path}; board-managed edits must use the wiki UI.`);
}
}
function assertRawPath(path: string): string {
const normalized = assertWikiPath(path);
if (!normalized.startsWith("raw/")) {
throw new Error(`Source path must stay inside raw/: ${path}`);
}
return normalized;
}
function tableName(namespace: string, table: string): string {
return `${namespace}.${table}`;
}
function spaceTable(ctx: PluginContext): string {
return tableName(ctx.db.namespace, "wiki_spaces");
}
function bindingTable(ctx: PluginContext): string {
return tableName(ctx.db.namespace, "wiki_resource_bindings");
}
function distillationCursorTable(ctx: PluginContext): string {
return tableName(ctx.db.namespace, "paperclip_distillation_cursors");View on GitHub (pinned to 67001ec6eb)
Solutions
- Prefix all raw asset paths with 'raw/' before calling the raw-source API.
- Use spaceRelativePath with a known raw root when constructing paths.
- Reject raw API requests at the boundary if the path does not start with 'raw/'.
Example fix
// before
await writeRawSource(ctx, { companyId, path: "diagrams/arch.png" });
// after
await writeRawSource(ctx, { companyId, path: "raw/diagrams/arch.png" }); Defensive patterns
Strategy: validation
Validate before calling
function ensureRawPrefix(path) {
const t = String(path).trim().replace(/^\/+/, "");
if (!t.startsWith("raw/")) throw new Error(`Source path must stay inside raw/: ${path}`);
return t;
} Type guard
function isRawPath(path) {
return String(path ?? "").trim().replace(/^\/+/, "").startsWith("raw/");
} Try / catch
try {
await writeRawSource(ctx, { companyId, path, content });
} catch (err) {
if (/must stay inside raw\//.test(err.message)) {
return writeRawSource(ctx, { companyId, path: `raw/${String(path).replace(/^\/+/, "")}`, content });
}
throw err;
} Prevention
- Always prefix raw asset paths with raw/.
- Use spaceRelativePath with a known raw root.
- Reject raw API requests missing the prefix.
When it happens
Trigger: Calling a raw-source write/read API with a path like 'assets/foo.png', 'wiki/foo.png', or 'foo.png'.
Common situations: Forgetting the raw/ prefix when constructing an asset path; reusing a page path for a raw asset; UI upload form omitting the prefix.
Related errors
- Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: $
- Wiki page path must be a markdown file: ${path}
- 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_
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/80dba6545526bf65.
Report an issue: GitHub.