paperclipai/paperclip · error
Cloud control assertion is not a compact JWS
Error message
Cloud control assertion is not a compact JWS
What it means
verifyCloudControlAssertion validates an EdDSA-signed compact JWS assertion used for cloud control-plane requests. The very first structural check splits the token on '.' and requires exactly three non-empty parts (header.payload.signature). This error is thrown when the input is not a three-segment, dot-delimited compact JWS at all.
Solutions
- Log the received assertion shape (segment count, lengths only — never the token itself) to confirm whether it has 3 dot-separated non-empty parts
- Fix the client/signer to emit a proper compact JWS: base64url(header).base64url(payload).base64url(signature) with EdDSA/Ed25519
- Check that no intermediary rewrites, trims, or wraps the Authorization header value
- Reject at the client before sending: validate the token format locally with the validation snippet below
Example fix
// before
await fetch(api, { headers: { authorization: `Bearer ${assertion.trim()}` } });
// after
const compact = assertion.trim();
if (compact.split(".").length !== 3 || compact.split(".").some(p => p.length === 0)) {
throw new Error("refusing to send: assertion is not a compact JWS");
}
await fetch(api, { headers: { authorization: `Bearer ${compact}` } }); Defensive patterns
Strategy: validation
Validate before calling
function isCompactJws(token) {
if (typeof token !== "string") return false;
const parts = token.split(".");
return parts.length === 3 && parts.every(p => p.length > 0);
}
if (!isCompactJws(assertion)) throw new Error("assertion must be a compact JWS before sending"); Type guard
const isCompactJws = (v: unknown): v is string =>
typeof v === "string" && v.split(".").length === 3 && v.split(".").every(p => p.length > 0); Try / catch
try {
const claims = await verifyCloudControlAssertion({ compactJws: token, expectedAction });
} catch (e) {
if (e.message === "Cloud control assertion is not a compact JWS") {
return respond(401, "malformed assertion"); // structural problem: do not retry the same token
}
throw e;
} Prevention
- Never build tokens by string concatenation; use a JWS signing helper that guarantees the three-part form
- Log only segment counts/lengths, never the token, when debugging malformed assertions
- Reject malformed tokens client-side before network calls
When it happens
Trigger: cloudControlMiddleware / verify receives an Authorization header or assertion value that is empty, whitespace, a raw JWT with fewer/more than three segments, a bearer token of another kind, a base64-encoded blob, or a JWS that was truncated or URL-mangled in transit.
Common situations: A client sends a PASETO or opaque token instead of the expected compact JWS; a proxy or reverse proxy stripped or rewrote the header; the caller URL-encoded the token introducing percent escapes; a misconfigured SDK sends its own API key instead of a cloud control assertion.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Cloud control protected header is invalid
- Cloud control signature is invalid
- Cloud control assertion does not authorize this action
- Cloud control assertion is expired or has an invalid…
- Cloud control assertion request id is invalid
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/7d6cbae1052cbe76.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/cloud-runtime-identity.ts:512
/**
* Verify a Cloud control assertion for one exact action on this instance.
* Signed with the same key set as the runtime identity assertion
* (PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS) but under its own JWS type and
* audience. Instances without a Cloud stack identity reject every assertion —
* the feature is inert when self-hosted.
*/
export function verifyCloudControlAssertion(input: {
compactJws: string;
expectedAction: CloudControlAction;
env?: NodeJS.ProcessEnv;
now?: Date;
}): CloudControlClaims {
const env = input.env ?? process.env;
const now = input.now ?? new Date();
const parts = input.compactJws.split(".");
if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
throw new Error("Cloud control assertion is not a compact JWS");
}
const [encodedHeader, encodedPayload, encodedSignature] = parts;
const header = decodeJsonPart(encodedHeader, "protected header");
if (
header.alg !== "EdDSA"
|| header.typ !== CLOUD_CONTROL_JWS_TYPE
|| typeof header.kid !== "string"
|| !header.kid
) {
throw new Error("Cloud control protected header is invalid");
}
const key = publicKeyForKid(env, header.kid);
const signature = Buffer.from(encodedSignature, "base64url");
const signingInput = Buffer.from(`${encodedHeader}.${encodedPayload}`, "ascii");
if (!verify(null, signingInput, key, signature)) {
throw new Error("Cloud control signature is invalid");
}
View on GitHub (pinned to 3f1d897a7c)