paperclipai/paperclip · error · Error

Public viewer asset differs from trusted build: ${file}

Error message

Public viewer asset differs from trusted build: ${file}

What it means

Files under viewer/ are compared byte-for-byte against a trusted viewer build (trustedViewerFiles). If a viewer file is missing from the trusted build or its bytes differ, the script aborts naming the file, ensuring only known-good, unmodified viewer assets are published.

Source

Thrown at packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs:171

    );
  }
  for (const file of files) {
    if (!isPublicProtocolEvalPath(file)) {
      throw new Error(
        `Refusing non-allowlisted public protocol eval path ${file}`,
      );
    }
    const absolute = resolve(root, ...file.split("/"));
    const metadata = await stat(absolute);
    if (metadata.size === 0 || metadata.size > 12 * 1024 * 1024) {
      throw new Error(
        `Public protocol eval file exceeds its size boundary: ${file}`,
      );
    }
    if (file.startsWith("viewer/")) {
      const expected = viewer?.files.get(file);
      if (!expected || !expected.equals(await readFile(absolute)))
        throw new Error(
          `Public viewer asset differs from trusted build: ${file}`,
        );
      continue;
    }
    const content = await readFile(absolute, "utf8");
    const richAttempt = /^attempts\/[^/]+\/index\.html$/.test(file);
    const payload = richAttempt
      ? validatePublicViewerPage(content, viewer.index)
      : null;
    if (!richAttempt) {
      for (const pattern of CREDENTIAL_PATTERNS) {
        if (pattern.test(content))
          throw new Error(
            `Public report contains credential/session material: ${file}`,
          );
      }
      if (extname(file) !== ".html") continue;
      for (const pattern of ACTIVE_HTML_PATTERNS) {

View on GitHub (pinned to 01ad858492)

Solutions

  1. Re-copy or rebuild the viewer assets from the same trusted viewerRoot the script compares against, then re-run.
  2. Ensure no post-processing step modifies files under viewer/ after they are placed in the report.
  3. Clear the report's viewer/ directory and regenerate so it exactly matches the trusted build.

Example fix

# before: stale/edited viewer asset
public-report/viewer/app.js  (hand-edited)
# after
$ rm -rf public-report/viewer && cp -R trusted-viewer/dist public-report/viewer
$ node scripts/publish-runner-protocol-eval-history.mjs ...
Defensive patterns

Strategy: validation

Validate before calling

import { createHash } from 'node:crypto';
import { readdirSync, readFileSync } from 'node:fs';
for (const rel of listViewerFiles(reportRoot)) {
  const trustedPath = `${trustedViewerRoot}/${rel.slice('viewer/'.length)}`;
  const a = createHash('sha256').update(readFileSync(`${reportRoot}/${rel}`)).digest('hex');
  const b = createHash('sha256').update(readFileSync(trustedPath)).digest('hex');
  if (a !== b) throw new Error(`viewer asset differs from trusted build: ${rel}`);
}

Try / catch

try {
  await publishReport(root);
} catch (err) {
  if (String(err.message).startsWith('Public viewer asset differs from trusted build')) {
    console.error('Restore viewer/ from the trusted build before publishing:', err.message);
  } else throw err;
}

Prevention

When it happens

Trigger: Publishing when a viewer/ file was modified after the trusted build (post-processing, minifier rerun, manual edit) or when the viewer/ directory content does not match the trusted viewerRoot used for comparison.

Common situations: Rebuilding the viewer with different tooling/settings than the trusted build; a script rewrote viewer asset hashes; stale viewer/ files from a previous build mixed with new ones; pointing the script at a different viewer build than the one copied into the report.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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