paperclipai/paperclip · error

Cloud runtime identity claims are incomplete

Error message

Cloud runtime identity claims are incomplete

What it means

Thrown by verifyClaims when the decoded payload is valid JSON but lacks the required claims or has wrong types: v must be 1, iss/aud must match the expected issuer/audience constants, and sub, claimId, previousOrigin, canonicalOrigin, stackSlug must be strings, iat/exp must be integers. This guards against assertions missing fields this identity protocol depends on.

Source

Thrown at server/src/services/cloud-runtime-identity.ts:302

  }

  const payload = decodeJsonPart(encodedPayload, "payload");
  const nowSeconds = Math.floor(input.now.getTime() / 1000);
  if (
    payload.v !== 1
    || payload.iss !== CLOUD_RUNTIME_IDENTITY_ISSUER
    || payload.aud !== CLOUD_RUNTIME_IDENTITY_AUDIENCE
    || typeof payload.sub !== "string"
    || typeof payload.claimId !== "string"
    || typeof payload.previousOrigin !== "string"
    || typeof payload.canonicalOrigin !== "string"
    || typeof payload.stackSlug !== "string"
    || typeof payload.iat !== "number"
    || !Number.isInteger(payload.iat)
    || typeof payload.exp !== "number"
    || !Number.isInteger(payload.exp)
  ) {
    throw new Error("Cloud runtime identity claims are incomplete");
  }
  if (
    payload.exp <= nowSeconds
    || payload.iat > nowSeconds + MAX_CLOCK_SKEW_SECONDS
    || payload.exp <= payload.iat
    || payload.exp - payload.iat > MAX_ASSERTION_LIFETIME_SECONDS
  ) {
    throw new Error("Cloud runtime identity assertion is expired or has an invalid lifetime");
  }
  return payload as RuntimeIdentityClaims;
}

/** Verify that an assertion is signed for this exact, still-unclaimed instance. */
export function verifyCloudRuntimeIdentityAssertion(input: {
  compactJws: string;
  env?: NodeJS.ProcessEnv;
  now?: Date;
  expectedPreviousOrigin: string | null;

View on GitHub (pinned to 01ad858492)

Solutions

  1. Re-mint the assertion with the current protocol version (v: 1) and the exact claim set expected here
  2. Ensure iat/exp are integer Unix seconds, not milliseconds or strings
  3. Set iss and aud to the values of CLOUD_RUNTIME_IDENTITY_ISSUER and CLOUD_RUNTIME_IDENTITY_AUDIENCE constants
  4. Base64url-decode the payload segment and diff its keys against the required claims list in verifyClaims

Example fix

// before: ms timestamps
payload.iat = Date.now(); // 1725879600000
// after: integer unix seconds
payload.iat = Math.floor(Date.now() / 1000);
Defensive patterns

Strategy: validation

Validate before calling

interface ExpectedClaims { v: number; iss: string; aud: string; sub: string; claimId: string; previousOrigin: string; canonicalOrigin: string; stackSlug: string; iat: number; exp: number; }
function hasRequiredClaims(p: Record<string, unknown>): p is ExpectedClaims {
  return p.v === 1 && typeof p.iss === "string" && typeof p.aud === "string"
    && ["sub","claimId","previousOrigin","canonicalOrigin","stackSlug"].every(k => typeof p[k] === "string")
    && Number.isInteger(p.iat) && Number.isInteger(p.exp);
}

Try / catch

try {
  verifyCloudRuntimeIdentityAssertion({ compactJws: assertion, expectedPreviousOrigin: prev });
} catch (e) {
  if (String((e as Error).message).includes("claims are incomplete")) {
    logger.error("Assertion payload missing required identity claims — check minter protocol version", { error: e });
  } else throw e;
}

Prevention

When it happens

Trigger: Payload parses as an object but any of v, iss, aud, sub, claimId, previousOrigin, canonicalOrigin, stackSlug is missing/wrong-typed, iss/aud do not equal CLOUD_RUNTIME_IDENTITY_ISSUER/AUDIENCE, v !== 1, or iat/exp are non-integer numbers (e.g. seconds with fractional part or milliseconds).

Common situations: Assertions minted by an older protocol version (v:0) after a server upgrade; a generic JWT library producing numeric-string iat/exp or millisecond timestamps; tokens from a different product/issuer reusing the same endpoint; custom claim names used instead of the protocol's exact claim keys.

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/2c85c76785c8f105. Report an issue: GitHub.