paperclipai/paperclip · error · Error

Public replay contains an unprojected item

Error message

Public replay contains an unprojected item

What it means

Thrown by validatePublicChatPayload when a turn item has a 'kind' outside the allowlist user_message, agent_message, tool_activity, system_notice. Public replays expose only these projected item kinds; any other kind (e.g. internal-only items) indicates an unprojected item leaked through.

Source

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

      call,
      "id turnId operationId version providerRequest dispatchedCommand outcome result redactions threadAnchorId",
    );
    fields(call.result, "outcome detail");
    if (call.result.detail !== "Tool payload withheld from public replay.")
      throw new Error("Public replay contains raw call evidence");
  }
  for (const turn of payload.view.turns ?? []) {
    fields(turn, "id ordinal mode toolCallCount at stoppedByUser items");
    for (const item of turn.items ?? []) {
      if (
        ![
          "user_message",
          "agent_message",
          "tool_activity",
          "system_notice",
        ].includes(item.kind)
      )
        throw new Error("Public replay contains an unprojected item");
      const shapes = {
        user_message: "kind id at author body streaming",
        agent_message: "kind id at author body streaming",
        tool_activity:
          "kind id at operationId status summary input result evidenceRef",
        system_notice: "kind id at glyph text evidenceRef",
      };
      fields(item, shapes[item.kind]);
      if (item.evidenceRef) fields(item.evidenceRef, "section recordId");
      if (
        item.kind === "tool_activity" &&
        (JSON.stringify(item.input) !==
          JSON.stringify({
            detail: "Arguments withheld from public replay.",
          }) ||
          Object.keys(item.result).sort().join(",") !== "detail,outcome" ||
          item.result.detail !== "Tool payload withheld from public replay.")
      )

View on GitHub (pinned to 01ad858492)

Solutions

  1. Update the projection step to map or drop the unknown item kind before building the public view.
  2. If the kind is legitimately public, add it to the allowlist in validatePublicChatPayload together with a shape entry.
  3. Regenerate the public replay from the original run after fixing the projector.

Example fix

// before
items.push({ kind: 'internal_debug', ... });
// after
if (PUBLIC_KINDS.has(item.kind)) items.push(projectItem(item)); // internal_debug dropped
Defensive patterns

Strategy: validation

Validate before calling

const KINDS = ['user_message','agent_message','tool_activity','system_notice'];
if (turns.some(t => (t.items ?? []).some(i => !KINDS.includes(i.kind)))) throw new Error('unknown item kind in public view');

Type guard

function isPublicItemKind(k) { return ['user_message','agent_message','tool_activity','system_notice'].includes(k); }

Prevention

When it happens

Trigger: Validating a payload where any view.turns[i].items[j].kind is not one of the four allowed kinds.

Common situations: A new internal item kind added upstream that the projector does not map or drop; replaying an old run whose items contain retired kinds; a projection filter accidentally disabled.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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