paperclipai/paperclip · error
Cloud control assertion stack does not match this instance
Error message
Cloud control assertion stack does not match this instance
What it means
verifyCloudControlAssertion binds every assertion to a specific cloud stack. This error is thrown when PAPERCLIP_CLOUD_STACK_ID is not configured on this instance, or when the payload's sub claim does not equal the configured stack id. It prevents an assertion minted for one stack from controlling another.
Solutions
- Set PAPERCLIP_CLOUD_STACK_ID on the instance to the stack id this runtime belongs to and restart the server
- Ensure the assertion issuer uses that same stack id as the sub claim when minting tokens
- Check deployment config: confirm the client and instance point at the same environment/stack (staging vs production mix-up)
- Re-issue assertions after any stack rename or infra migration
Example fix
// before # instance env (missing) // after PAPERCLIP_CLOUD_STACK_ID=stack_01h_example # must equal the sub claim of minted assertions
Defensive patterns
Strategy: validation
Validate before calling
const stackId = process.env.PAPERCLIP_CLOUD_STACK_ID;
if (!stackId) throw new Error("PAPERCLIP_CLOUD_STACK_ID must be set before accepting control assertions");
if (minted.sub !== stackId) throw new Error(`assertion sub ${minted.sub} does not match stack ${stackId}`); Try / catch
try {
return verifyCloudControlAssertion({ compactJws: token, expectedAction });
} catch (e) {
if (e.message === "Cloud control assertion stack does not match this instance") {
return respond(403, "assertion is for a different stack"); // cross-environment token: do not retry here
}
throw e;
} Prevention
- Fail fast at startup if PAPERCLIP_CLOUD_STACK_ID is unset in cloud deployments (see initializeCloudRuntimeIdentity)
- Configure the assertion issuer with the same stack id used by the target instance
- Keep per-environment configs separate to avoid staging tokens hitting production
When it happens
Trigger: A token whose sub names a different stack is sent to this instance; PAPERCLIP_CLOUD_STACK_ID is unset/empty on the verifying instance (so configuredStackId is undefined and the guard fails); the client was configured with the wrong stack id when minting assertions.
Common situations: Environment variables not propagated to a replica or canary deployment; a control-plane client pointing at the wrong environment (staging token against production instance); stack renamed/recreated without re-issuing assertions; copy-pasted env config between deployments.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Cloud control assertion does not authorize this action
- CreateOS API URL must be an HTTPS origin (optionally ending…
- Custom CreateOS API endpoints require an explicit…
- organization_authorization_required
- paperclip_runner_chat_attachment_principal_denied
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/3bf5756225177d26.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/cloud-runtime-identity.ts:549
const payload = decodeJsonPart(encodedPayload, "payload");
const configuredStackId = nonEmpty(env.PAPERCLIP_CLOUD_STACK_ID);
const nowSeconds = Math.floor(now.getTime() / 1000);
if (
payload.v !== 1
|| payload.iss !== CLOUD_RUNTIME_IDENTITY_ISSUER
|| payload.aud !== CLOUD_CONTROL_AUDIENCE
|| typeof payload.sub !== "string"
|| typeof payload.action !== "string"
|| typeof payload.requestId !== "string"
|| typeof payload.iat !== "number"
|| !Number.isInteger(payload.iat)
|| typeof payload.exp !== "number"
|| !Number.isInteger(payload.exp)
) {
throw new Error("Cloud control claims are incomplete");
}
if (!configuredStackId || payload.sub !== configuredStackId) {
throw new Error("Cloud control assertion stack does not match this instance");
}
if (
!(CLOUD_CONTROL_ACTIONS as readonly string[]).includes(payload.action)
|| payload.action !== input.expectedAction
) {
throw new Error("Cloud control assertion does not authorize this action");
}
if (
!payload.requestId
|| payload.requestId.trim() !== payload.requestId
|| payload.requestId.length > 256
) {
throw new Error("Cloud control assertion request id is invalid");
}
if (
payload.exp <= nowSeconds
|| payload.iat > nowSeconds + MAX_CLOCK_SKEW_SECONDS
|| payload.exp <= payload.iatView on GitHub (pinned to 3f1d897a7c)