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

  1. Normalize the path client-side: strip leading slashes, collapse repeated slashes, reject '.' and '..' segments.
  2. Validate the path is non-empty before calling the API.
  3. Reject backslashes in path inputs at the form boundary.
  4. 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

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


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/acb2ff6ad4577c87. Report an issue: GitHub.