paperclipai/paperclip · error · Error

Incomplete trusted viewer build

Error message

Incomplete trusted viewer build

What it means

After collecting assets, trustedViewerFiles() performs a sanity check that the viewer build is actually usable: at least one .js asset must exist and index.html must contain a module script tag ('<script type="module"'). If either is missing, the build is considered truncated or wrong, and "Incomplete trusted viewer build" is thrown rather than publishing a shell that cannot load the report.

Source

Thrown at packages/paperclip-runner/scripts/public-eval-viewer.mjs:55

  )
    throw new Error("Trusted viewer must not use symlinks");
  const index = await readFile(join(viewerRoot, "index.html"), "utf8");
  const files = new Map();
  for (const entry of await readdir(join(viewerRoot, "assets"), {
    withFileTypes: true,
  })) {
    if (!entry.isFile() || entry.isSymbolicLink() || !ASSET.test(entry.name))
      throw new Error("Unexpected trusted viewer asset");
    files.set(
      `viewer/assets/${entry.name}`,
      await readFile(join(viewerRoot, "assets", entry.name)),
    );
  }
  if (
    ![...files.keys()].some((name) => name.endsWith(".js")) ||
    !index.includes('<script type="module"')
  )
    throw new Error("Incomplete trusted viewer build");
  return { index, files };
}

export function validatePublicChatPayload(payload) {
  if (
    payload?.publication?.schema !== PUBLIC_CHAT_SCHEMA ||
    payload.view?.sessionId !== "public-report" ||
    payload.view?.composer?.state !== "disabled" ||
    payload.view?.connection?.state !== "closed" ||
    payload.devtools !== null
  )
    throw new Error(
      "Public attempt must contain the read-only public chat projection",
    );
  const allowed = new Set([
    "attemptId",
    "caseId",
    "disposition",

View on GitHub (pinned to 01ad858492)

Solutions

  1. Rebuild the viewer so assets/ contains at least one .js entry and index.html keeps its <script type="module"> tag, then retry.
  2. Verify viewerRoot points at the built viewer output (containing index.html and assets/), not a source or placeholder directory.
  3. Diff index.html against a known-good built viewer to confirm the module script tag was not removed by templating or post-processing.
  4. If the viewer build format legitimately changed, update the '<script type="module"' check and the PUBLIC_VIEWER_DATA/publicViewerShell expectations in public-eval-viewer.mjs together.

Example fix

// before: placeholder index.html without a module script
<div id="root"></div>
// after: rebuild so index.html includes
<script type="module" crossorigin src="./assets/index-abc123.js"></script>
Defensive patterns

Strategy: validation

Validate before calling

const index = await readFile(join(root, "index.html"), "utf8");
const hasJs = (await readdir(join(root, "assets"))).some((n) => n.endsWith(".js"));
if (!hasJs || !index.includes('<script type="module"')) throw new Error("Viewer build incomplete");

Try / catch

try {
  await trustedViewerFiles(viewerRoot);
} catch (err) {
  if (err.message === "Incomplete trusted viewer build") {
    console.error("Viewer build at", viewerRoot, "is truncated; rerun the viewer build");
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling trustedViewerFiles(viewerRoot) where assets/ contains no .js file (CSS/fonts only), or where index.html was hand-edited/emptied so the '<script type="module"' substring is absent (e.g. renamed, minified differently, or the file is a placeholder).

Common situations: Partial or interrupted build output copied to viewerRoot; serving the wrong directory (an empty template instead of the built viewer); an old viewer version whose index.html format changed; someone stripping the module script during templating.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/6871b34a8eafd82d. Report an issue: GitHub.