paperclipai/paperclip · error

ACPX provider identity is incomplete

Error message

ACPX provider identity is incomplete

What it means

parseProviderIdentity rehydrates a persisted ACPX provider identity from stored/serialized state. It requires eight string fields — normalizedSessionId, acpxRecordId, backendSessionId, agentSessionId, profileDigest, workspaceDigest, requestedModel, effectiveModel — each a non-empty string of at most 240 characters. If any is missing, not a string, empty, or longer than 240 characters, it throws "ACPX provider identity is incomplete" rather than returning a partially populated identity.

Source

Thrown at packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts:63

  const requiredStrings = [
    "normalizedSessionId",
    "acpxRecordId",
    "backendSessionId",
    "agentSessionId",
    "profileDigest",
    "workspaceDigest",
    "requestedModel",
    "effectiveModel",
  ] as const;
  if (
    requiredStrings.some(
      (key) =>
        typeof identity[key] !== "string" ||
        identity[key].length === 0 ||
        identity[key].length > 240,
    )
  ) {
    throw new Error("ACPX provider identity is incomplete");
  }
  const permissionMode = identity.permissionMode;
  if (
    permissionMode !== undefined &&
    permissionMode !== "approve-all" &&
    permissionMode !== "approve-reads" &&
    permissionMode !== "deny-all"
  ) {
    throw new Error(
      "ACPX provider identity contains an invalid permission mode",
    );
  }
  const fenceCandidates = identity.providerLifetimeFenceCandidates;
  if (
    !Array.isArray(fenceCandidates) ||
    fenceCandidates.length !== 3 ||
    fenceCandidates.some(
      (candidate) =>

View on GitHub (pinned to 01ad858492)

Solutions

  1. Inspect the persisted provider identity object and populate every required key (normalizedSessionId, acpxRecordId, backendSessionId, agentSessionId, profileDigest, workspaceDigest, requestedModel, effectiveModel) with non-empty strings ≤240 chars.
  2. If the record predates a schema change, re-create the session/identity via the normal launch path instead of loading the stale record.
  3. Check the serialization path: ensure undefined/empty fields are not dropped silently by JSON.stringify or partial-update DB writes.
  4. Validate before persisting (same field checks at write time) so incomplete records can never be stored.

Example fix

// before
const identity = { kind: "acpx", normalizedSessionId: session.id, acpxRecordId: record.id };
parseProviderIdentity(identity); // throws
// after
const identity = {
  kind: "acpx",
  normalizedSessionId: session.id,
  acpxRecordId: record.id,
  backendSessionId: backend.id,
  agentSessionId: agent.id,
  profileDigest: profile.digest,
  workspaceDigest: workspace.digest,
  requestedModel: requested,
  effectiveModel: effective,
};
parseProviderIdentity(identity); // ok
Defensive patterns

Strategy: type-guard

Validate before calling

const REQUIRED_KEYS = ["normalizedSessionId","acpxRecordId","backendSessionId","agentSessionId","profileDigest","workspaceDigest","requestedModel","effectiveModel"] as const;
const complete = REQUIRED_KEYS.every((k) =>
  typeof identity[k] === "string" && identity[k].length > 0 && identity[k].length <= 240
);
if (!complete) throw new Error("refusing to persist/load incomplete ACPX identity");

Type guard

function isCompleteApxIdentity(v: unknown): v is Record<string, string> {
  if (typeof v !== "object" || v === null) return false;
  const r = v as Record<string, unknown>;
  if (r.kind !== "acpx") return false;
  return (["normalizedSessionId","acpxRecordId","backendSessionId","agentSessionId","profileDigest","workspaceDigest","requestedModel","effectiveModel"] as const)
    .every((k) => typeof r[k] === "string" && (r[k] as string).length > 0 && (r[k] as string).length <= 240);
}

Try / catch

let identity: PersistedHarnessProviderIdentity | undefined;
try {
  identity = parseProviderIdentity(stored);
} catch (error) {
  if (error instanceof Error && error.message === "ACPX provider identity is incomplete") {
    identity = undefined; // fall back to relaunching the session to rebuild identity
  } else {
    throw error;
  }
}

Prevention

When it happens

Trigger: Calling parseProviderIdentity on an object with kind "acpx" where any required key is absent, null, a non-string (e.g. number), "", or >240 chars — e.g. parseProviderIdentity({ kind: "acpx", normalizedSessionId: "s", acpxRecordId: "r" }) (all other keys missing) or a stored record where backendSessionId was serialized as undefined.

Common situations: Schema/version drift where an older persisted record predates a newly required field; JSON round-trip dropping keys with undefined values; manual edits or partial writes to the persisted provider record; corruption of the digest fields by a failed profile/workspace digest computation that stored "".

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/1a119b5f768b209c. Report an issue: GitHub.