paperclipai/paperclip · critical · Error

Public replay contains a private field

Error message

Public replay contains a private field

What it means

While recursing through object entries, visit() rejects any non-null child stored under a private field name matching ^(managedProfile|acpxProfile|providerTrace|mockState|stateHistory|trace|environment|env|apiKey|accessToken|password|secret)$ (case-insensitive). This is a final catch-all so private runtime state cannot be smuggled into the public replay even if the shape allowlists above were updated; violation throws "Public replay contains a private field".

Source

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

        !["public-report", "unknown", "redacted"].includes(value)
      )
        throw new Error("Public replay contains a private session identity");
      for (const pattern of SECRET_TEXT) {
        pattern.lastIndex = 0;
        if (pattern.test(value))
          throw new Error(
            "Public replay contains credential or private reference material",
          );
      }
    } else if (value && typeof value === "object") {
      for (const [name, child] of Object.entries(value)) {
        if (
          /^(?:managedProfile|acpxProfile|providerTrace|mockState|stateHistory|trace|environment|env|apiKey|accessToken|password|secret)$/i.test(
            name,
          ) &&
          child != null
        )
          throw new Error("Public replay contains a private field");
        visit(child, name);
      }
    }
  };
  visit(payload);
  for (const section of [
    "tools",
    "authorization",
    "control_plane",
    "runner",
    "state",
    "traceability",
    "parity",
  ]) {
    if (
      !Array.isArray(payload.view.evidence?.[section]) ||
      payload.view.evidence[section].length
    )

View on GitHub (pinned to 01ad858492)

Solutions

  1. Delete or null the offending private field in the projection step before validation.
  2. Project each nested section explicitly (pick allowlisted keys) instead of spreading whole internal objects into the public payload.
  3. Extend the public projector to cover the newly added section containing the private field.
  4. Regenerate the payload and revalidate; ensure the field isn't reintroduced by a shared builder used for both internal and public payloads.

Example fix

// before
turnItems: internalItems.map((i) => ({ ...i, environment: i.env })),
// after
turnItems: internalItems.map(({ environment, ...rest }) => rest),
Defensive patterns

Strategy: validation

Validate before calling

const PRIVATE_FIELD = /^(?:managedProfile|acpxProfile|providerTrace|mockState|stateHistory|trace|environment|env|apiKey|accessToken|password|secret)$/i;
const findPrivate = (v) => {
  if (v && typeof v === "object") for (const [k, c] of Object.entries(v)) {
    if (PRIVATE_FIELD.test(k) && c != null) return k;
    const hit = findPrivate(c); if (hit) return hit;
  }
  return null;
};
if (findPrivate(payload)) console.warn("private field present:", findPrivate(payload));

Type guard

const hasNoPrivateFields = (payload) => findPrivate(payload) === null;

Try / catch

try {
  validatePublicChatPayload(payload);
} catch (err) {
  if (err.message === "Public replay contains a private field") {
    throw new Error("A private field (trace/env/profile/credential-shaped key) is non-null in the payload; strip it in the projector");
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling validatePublicChatPayload with a payload where any nested object has a key like apiKey, env, trace, mockState, stateHistory, providerTrace, environment, accessToken, password, or secret (any casing) with a non-null value — e.g. a tool_activity item embedding call.environment or a run retaining trace objects.

Common situations: A new projected section includes debugging state (mockState/stateHistory) added for internal tooling; a turn item captures the call environment; an internal payload object was spread into the public payload carrying a trace field.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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