mastra-ai/mastra · error · MastraClientError
Failed to canonicalize A2A Agent Card for signature verifica
Error message
Failed to canonicalize A2A Agent Card for signature verification
What it means
verifyAgentCardSignatureIfPresent signs verification over the canonical JSON form of the Agent Card (RFC 8785 via the `canonicalize` package). After stripping the `signatures` array, canonicalization returned a falsy value (null/empty), which means the card payload could not be deterministically serialized, so no JWS can be built that matches what the signer produced. The library throws MastraClientError(200,'OK') rather than proceeding with a payload that would never verify.
Source
Thrown at client-sdks/client-js/src/utils/verify-agent-card-signature.ts:102
return importSPKI(key, algorithm);
}
return importJWK(key as JWK, algorithm);
}
export async function verifyAgentCardSignatureIfPresent(
agentCard: AgentCard,
options: VerifyAgentCardSignatureOptions,
): Promise<AgentCard> {
const signatures = agentCard.signatures ?? [];
if (signatures.length === 0) {
return agentCard;
}
const canonicalPayload = canonicalize(stripAgentCardSignatures(agentCard));
if (!canonicalPayload) {
throw new MastraClientError(200, 'OK', 'Failed to canonicalize A2A Agent Card for signature verification');
}
const allowedAlgorithms = options.algorithms ?? [...DEFAULT_AGENT_CARD_SIGNATURE_ALGORITHMS];
const encodedPayload = base64url.encode(canonicalPayload);
const verificationErrors: string[] = [];
for (const [index, signature] of signatures.entries()) {
try {
const compactJws = `${signature.protected}.${encodedPayload}.${signature.signature}`;
const protectedHeader = decodeProtectedHeader(compactJws);
if (typeof protectedHeader.alg !== 'string') {
throw new Error('Agent Card signature is missing a protected "alg" header');
}
if (!allowedAlgorithms.includes(protectedHeader.alg)) {
throw new Error(`Agent Card signature algorithm "${protectedHeader.alg}" is not allowed`);
}View on GitHub (pinned to 75dd419e61)
Solutions
- Inspect the Agent Card returned by the server (log it before verification) and remove/fix any field that is not valid JSON-compatible data.
- Ensure the server returns a well-formed, complete Agent Card (an empty or partial card can canonicalize to empty).
- Update @mastra/core and client-js to matching versions so the AgentCard shape matches what the signer canonicalized.
- If the card is genuinely unsigned, strip the signatures array server-side so the verification path is skipped entirely.
Example fix
// before: verifying a mocked card fixture with extra non-JSON field card.customData = undefined; await getAgentCard(); // after: keep the card strictly JSON-serializable delete card.customData; await getAgentCard();
Defensive patterns
Strategy: validation
Validate before calling
// before calling the API, ensure the card you expect is JSON-canonicalizable
const res = await fetch(`${baseUrl}/.well-known/agent-card.json`);
const card = await res.json();
const stripped = { ...card };
delete stripped.signatures;
if (!JSON.stringify(stripped) || stripped === undefined) {
throw new Error('Agent Card is not JSON-serializable; verification would fail');
} Prevention
- Keep Agent Card fixtures strictly JSON-serializable (no undefined, functions, or cycles).
- Validate server responses against the AgentCard schema before enabling signature verification.
- Pin matching @mastra/core and client-js versions.
- Add a smoke test that runs canonicalize() over the real served card in CI.
When it happens
Trigger: Calling getAgentCard() on a client configured with signature verification when agentCard.signatures is non-empty and canonicalize(stripAgentCardSignatures(agentCard)) returns null/empty — i.e. the unsigned card JSON contains values RFC 8785 cannot represent (e.g. undefined fields serialized oddly, non-JSON-compatible values) or the card serializes to an empty string.
Common situations: A server (or proxy/MSW mock) returns an Agent Card whose fields include non-JSON-safe values or an unexpectedly empty/malformed body; a version change in @mastra/core/a2a AgentCard shape that breaks canonicalization; hand-crafted fixture cards in tests.
Related errors
- Agent Card signature is missing a protected "alg" header
- Agent Card signature algorithm "${protectedHeader.alg}" is n
- A2A Agent Card signature verification failed: ${verification
- Invalid or tampered state token
- Invalid state token signature
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/804331c0eedb1460.
Report an issue: GitHub.