paperclipai/paperclip · error · Error
Public report contains active or remote HTML: ${file}
Error message
Public report contains active or remote HTML: ${file} What it means
Thrown by validatePublicProtocolEvalReport when a non-rich-attempt HTML file in the public report matches one of the ACTIVE_HTML_PATTERNS: <script>, <iframe>, <object>, <embed>, <form> tags, inline on* event handlers, javascript: URLs, or absolute http(s):// src/href references. The published report must be fully static with no executable or remote-loading content, so active or remote-loading HTML is rejected before S3 upload.
Source
Thrown at packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs:191
);
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) {
if (pattern.test(content))
throw new Error(
`Public report contains active or remote HTML: ${file}`,
);
}
}
const navigation = payload
? [
payload.navigation?.suiteHref,
payload.navigation?.previous?.href,
payload.navigation?.next?.href,
].filter(Boolean)
: [];
for (const href of [...internalHtmlHrefs(content), ...navigation]) {
if (typeof href !== "string" || /[?:\\]|^\/|^[a-z]+:/i.test(href))
throw new Error(`Unsafe report navigation in ${file}`);
const clean = href.split("#", 1)[0].split("?", 1)[0];
const target = resolve(
root,
...file.split("/").slice(0, -1),View on GitHub (pinned to 01ad858492)
Solutions
- Locate the active HTML element or remote URL in the named file and remove it or replace with a static, relative reference.
- HTML-escape all agent-generated content when rendering report pages so embedded code displays as text, not markup.
- Serve all assets locally (viewer/assets/*.js|css|woff2) instead of linking remote CDNs.
- If the page is a rich attempt, render it as attempts/<id>/index.html (rich-attempt path) instead of the legacy attempts/<id>.html name.
Example fix
// before <script src="https://cdn.example.com/highlight.js"></script> // after <link rel="stylesheet" crossorigin href="./assets/app.css">
Defensive patterns
Strategy: validation
Validate before calling
const ACTIVE_HTML_PATTERNS = [ /<script\b/iu, /<iframe\b/iu, /<object\b/iu, /<embed\b/iu, /<form\b/iu, /\son[a-z]+\s*=/iu, /javascript\s*:/iu, /(?:src|href)\s*=\s*["'](?:https?:)?\/\//iu, ]; export const isStaticSafeHtml = (html) => !ACTIVE_HTML_PATTERNS.some((p) => p.test(html));
Type guard
const isStaticSafeHtml = (content) => !ACTIVE_HTML_PATTERNS.some((p) => p.test(content));
Try / catch
try {
await validatePublicProtocolEvalReport(reportRoot, { viewerRoot });
} catch (err) {
if (String(err.message).startsWith("Public report contains active or remote HTML")) {
console.error("Escape embedded agent HTML or remove script/iframe/remote references in the named page.");
}
throw err;
} Prevention
- Always HTML-escape agent-generated content when rendering report pages.
- Keep report templates free of analytics/marketing script snippets.
- Bundle all assets locally under viewer/assets instead of CDN links.
- Render rich attempts as attempts/<id>/index.html so they use the validated rich path.
When it happens
Trigger: Publishing a report whose index.html, tests/*.html, or attempts/<id>.html (legacy plain pages) contains e.g. <script src="https://cdn..."></script>, an <iframe>, an onclick= attribute, a javascript: link, or any src/href pointing at an absolute http(s) URL.
Common situations: Report generator pastes agent output containing raw HTML including script tags without escaping; a marketing/analytics snippet is left in the report template; screenshots are referenced via absolute CDN URLs instead of bundling assets locally; rich-viewer pages are misnamed as legacy attempts/<id>.html so they skip the rich-attempt path and get the strict static-HTML scan.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Public report contains credential/session material: ${file}
- Unsafe report navigation in ${file}
- Public report contains a broken or unsafe link in ${file}: $
- Access denied
- [plugin-kubernetes] egressMode=standard cannot enforce FQDN-
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/430c4e3b7b9c0d8f.
Report an issue: GitHub.