paperclipai/paperclip · error · Error
Invalid wiki path: ${path}
Error message
Invalid wiki path: ${path} What it means
Thrown by assertWikiPath when a path is empty after trimming, contains a backslash, or has any empty/dot/dot-dot segment after splitting on '/'. It is the first line of path-traversal defense shared by all wiki file APIs. The original (untrimmed) path is echoed back in the message.
Source
Thrown at packages/plugins/plugin-llm-wiki/src/wiki/core.ts:1164
{ space: defaultSpace, legacySettings: next },
);
await updateSpace(ctx, {
companyId: input.companyId,
wikiId: next.wikiId,
spaceSlug: DEFAULT_SPACE_SLUG,
settings: { paperclipIngestion: profile },
});
return next;
}
function assertWikiPath(path: string, options: { allowMetadata?: boolean } = {}): string {
const trimmed = path.trim().replace(/^\/+/, "");
if (
!trimmed ||
trimmed.includes("\\") ||
trimmed.split("/").some((segment) => segment === "" || segment === "." || segment === "..")
) {
throw new Error(`Invalid wiki path: ${path}`);
}
if (
trimmed !== ".gitignore" &&
trimmed !== "WIKI.md" &&
trimmed !== "AGENTS.md" &&
trimmed !== "IDEA.md" &&
trimmed !== "index.md" &&
trimmed !== "log.md" &&
!trimmed.startsWith("raw/") &&
!trimmed.startsWith("wiki/") &&
!(options.allowMetadata && trimmed.startsWith(".paperclip/"))
) {
throw new Error(`Wiki path must stay inside AGENTS.md, IDEA.md, raw/, or wiki/: ${path}`);
}
return trimmed;
}
function assertPagePath(path: string): string {View on GitHub (pinned to 67001ec6eb)
Solutions
- Normalize the path client-side: strip leading slashes, collapse repeated slashes, reject '.' and '..' segments.
- Validate the path is non-empty before calling the API.
- Reject backslashes in path inputs at the form boundary.
- Use spaceRelativePath to construct paths from trusted components.
Example fix
// before
await writePage(ctx, { companyId, path: req.body.path }); // user sends 'wiki/../etc'
// after
const clean = req.body.path.trim().replace(/^\/+/, "");
if (!clean || clean.includes("\\") || clean.split("/").some((s) => s === "" || s === "." || s === "..")) {
return res.status(400).json({ error: "Invalid wiki path" });
}
await writePage(ctx, { companyId, path: clean }); Defensive patterns
Strategy: validation
Validate before calling
function sanitizeWikiPath(path) {
const trimmed = String(path).trim().replace(/^\/+/, "");
if (
!trimmed ||
trimmed.includes("\\") ||
trimmed.split("/").some((s) => s === "" || s === "." || s === "..")
) {
throw new Error(`Invalid wiki path: ${path}`);
}
return trimmed;
} Type guard
function isValidWikiPathShape(path) {
const t = String(path ?? "").trim().replace(/^\/+/, "");
return !!t && !t.includes("\\") && !t.split("/").some((s) => s === "" || s === "." || s === "..");
} Try / catch
try {
await writePage(ctx, { companyId, path, content });
} catch (err) {
if (/Invalid wiki path/.test(err.message)) {
return res.status(400).json({ error: "Path must not be empty or contain backslashes, '.', or '..' segments." });
}
throw err;
} Prevention
- Normalize and validate paths at the form boundary.
- Reject backslashes outright.
- Build paths with spaceRelativePath from trusted components.
When it happens
Trigger: Any wiki write/read API that funnels through assertWikiPath (page writes, raw source writes, metadata) receives a path like '', '/', '//', 'a//b', 'a/./b', 'a/../b', or a Windows-style 'a\\b'.
Common situations: User input not normalized; paths joined with leading slashes; copy-pasted Windows paths; trailing slashes producing empty segments; malicious or accidental traversal attempts.
Related errors
- Wiki path must stay inside AGENTS.md, IDEA.md, raw/, or wiki
- Refusing to write export file outside output directory: ${re
- Invalid object key for company ${companyId}.
- sync operation ${label} path is not a confined absolute path
- sync operation ${label} path escapes its confinement root: $
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/acb2ff6ad4577c87.
Report an issue: GitHub.