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
- Re-mint the assertion with the current protocol version (v: 1) and the exact claim set expected here
- Ensure iat/exp are integer Unix seconds, not milliseconds or strings
- Set iss and aud to the values of CLOUD_RUNTIME_IDENTITY_ISSUER and CLOUD_RUNTIME_IDENTITY_AUDIENCE constants
- 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
- Keep minter and verifier on the same protocol version (v: 1); bump both together
- Use integer Unix seconds for iat/exp — Math.floor(Date.now()/1000)
- Copy claim names exactly from the RuntimeIdentityClaims type; no aliases
- Add a contract test that mints a token and runs it through verifyClaims
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
- Public attempt must contain the read-only public chat projec
- PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS is not configured
- Cloud runtime identity protected header is invalid
- Cloud runtime identity signature is invalid
- Access denied
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/2c85c76785c8f105.
Report an issue: GitHub.