mastra-ai/mastra · error
Failed to canonicalize A2A Agent Card for signing
Error message
Failed to canonicalize A2A Agent Card for signing
What it means
signAgentCard() serializes the agent card deterministically using the canonicalize() (RFC 8785 JSON canonicalization) library after stripping existing signatures. If canonicalize returns a falsy value — which happens for input that is not valid canonicalizable JSON (e.g. undefined/invalid values, non-JSON-safe data like undefined fields, NaN, or a non-object) — the function throws this error rather than signing non-canonical data.
Source
Thrown at packages/server/src/server/a2a/agent-card-signing.ts:84
function getDigestAlgorithm(algorithm: string): string {
if (algorithm.endsWith('256')) return 'sha256';
if (algorithm.endsWith('384')) return 'sha384';
if (algorithm.endsWith('512')) return 'sha512';
throw new Error(`Unsupported JWS algorithm for A2A Agent Card signing: ${algorithm}`);
}
export async function signAgentCard({
agentCard,
signing,
}: {
agentCard: AgentCard;
signing: A2AAgentCardSigningConfig;
}): Promise<AgentCard> {
const canonicalPayload = canonicalize(stripAgentCardSignatures(agentCard));
if (!canonicalPayload) {
throw new Error('Failed to canonicalize A2A Agent Card for signing');
}
const key = importSigningKey(signing);
const protectedHeader = getProtectedHeader(signing);
const encodedHeader = Buffer.from(JSON.stringify(protectedHeader), 'utf8').toString('base64url');
const encodedPayload = Buffer.from(canonicalPayload, 'utf8').toString('base64url');
const signingInput = `${encodedHeader}.${encodedPayload}`;
const signatureBuffer = crypto.sign(
getDigestAlgorithm(String(protectedHeader.alg)),
Buffer.from(signingInput, 'utf8'),
{
key,
...getSignatureOptions(String(protectedHeader.alg)),
},
);
const signatureValue = signatureBuffer.toString('base64url');
if (!encodedHeader || !signatureValue) {View on GitHub (pinned to 75dd419e61)
Solutions
- Log/inspect the agent card passed to signAgentCard and remove non-JSON-safe values (undefined, bigint, NaN, functions).
- Ensure the card is a plain JSON object — deep-clone through JSON.parse(JSON.stringify(card)) before signing if needed.
- Verify the card is fully populated (not undefined) before calling signAgentCard.
- Check the canonicalize dependency is correctly installed/Functioning (a broken import could yield a non-function whose result is falsy).
Example fix
// before
await signAgentCard({ agentCard: maybeUndefinedCard, signing });
// after
if (!agentCard || typeof agentCard !== 'object') throw new Error('Agent card missing');
const safeCard = JSON.parse(JSON.stringify(agentCard));
await signAgentCard({ agentCard: safeCard, signing }); Defensive patterns
Strategy: validation
Validate before calling
function isJsonSafe(v: unknown, seen = new Set()): boolean {
if (v === null || ['string','number','boolean'].includes(typeof v)) return true;
if (typeof v !== 'object' || seen.has(v)) return false;
seen.add(v);
return Object.values(v).every(x => isJsonSafe(x, seen));
}
// require isJsonSafe(agentCard) before signAgentCard Type guard
const isAgentCardObject = (c: unknown): c is Record<string, unknown> => typeof c === 'object' && c !== null && !Array.isArray(c);
Try / catch
let signedCard;
try {
signedCard = await signAgentCard({ agentCard, signing });
} catch (e) {
if (e.message.includes('Failed to canonicalize')) {
const safe = JSON.parse(JSON.stringify(agentCard));
signedCard = await signAgentCard({ agentCard: safe, signing });
} else throw e;
} Prevention
- Round-trip the agent card through JSON.parse(JSON.stringify(...)) before signing.
- Keep bigint/undefined/NaN values out of AgentCard fields.
- Assert the card is loaded and non-null before signing.
When it happens
Trigger: Calling signAgentCard with an AgentCard whose serialized form is not RFC 8785 canonicalizable — e.g. the card is undefined/null at runtime, or contains values JSON can't represent deterministically.
Common situations: Agent card constructed at runtime with undefined fields (bigints, undefined, functions in values); a storage/registry layer returning an empty or malformed card; version drift where the AgentCard type gained non-JSON-safe fields.
Related errors
- Unsupported JWS algorithm for A2A Agent Card signing: ${alg}
- Unsupported JWS algorithm for A2A Agent Card signing: ${algo
- Failed to create compact JWS for A2A Agent Card
- Expected a PEM-encoded public key or certificate string for
- Google service account private key signing failed (${(err as
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7bbbf22a6b1cd9a5.
Report an issue: GitHub.