clockworklabs/SpacetimeDB · error
Identity mismatch: token identity {token_identity:?} does no
Error message
Identity mismatch: token identity {token_identity:?} does not match computed identity {computed_identity:?} What it means
SpacetimeDB computes the caller identity as Identity::from_claims(iss, sub). If the token additionally carries an explicit identity claim, it must equal that computed value (crates/auth/src/identity.rs:121); otherwise conversion fails. This stops tokens from asserting an identity other than the one their iss/sub hash to.
Source
Thrown at crates/auth/src/identity.rs:121
return Err(anyhow::anyhow!("Issuer too long: {:?}", self.issuer));
}
if self.subject.len() > 128 {
return Err(anyhow::anyhow!("Subject too long: {:?}", self.subject));
}
// The issuer and subject must be non-empty.
if self.issuer.is_empty() {
return Err(anyhow::anyhow!("Issuer empty"));
}
if self.subject.is_empty() {
return Err(anyhow::anyhow!("Subject empty"));
}
let computed_identity = Identity::from_claims(&self.issuer, &self.subject);
// If an identity is provided, it must match the computed identity.
if let Some(token_identity) = self.identity
&& token_identity != computed_identity
{
return Err(anyhow::anyhow!(
"Identity mismatch: token identity {token_identity:?} does not match computed identity {computed_identity:?}",
));
}
Ok(SpacetimeIdentityClaims {
identity: computed_identity,
subject: self.subject,
issuer: self.issuer,
audience: self.audience,
iat: self.iat,
exp: self.exp,
extra: self.extra,
})
}
}
#[cfg(test)]
mod tests {View on GitHub (pinned to 524b4487d9)
Solutions
- Drop the identity claim from the token — it is optional and SpacetimeDB derives it from iss/sub
- Or recompute it: Identity::from_claims(current_iss, current_sub), and embed exactly that value
- After any iss/sub change, treat the result as a new identity and re-grant subscriptions/permissions to it
Example fix
// before (JWT payload)
{ "iss": "https://new-issuer.example.com", "sub": "12345", "identity": "<hash-of-old-issuer+sub>" }
// after
{ "iss": "https://new-issuer.example.com", "sub": "12345" } Defensive patterns
Strategy: validation
Validate before calling
// If you include an identity claim, verify it matches iss/sub before use:
// (identity = Identity::from_claims(iss, sub) server-side; keep them in sync or omit it)
function sanitizeClaims(claims: Record<string, unknown>) {
const { identity, ...rest } = claims;
if (identity !== undefined) {
console.warn('Dropping stale identity claim; SpacetimeDB derives it from iss/sub');
}
return rest;
} Prevention
- Simplest rule: never embed an identity claim; let SpacetimeDB derive it
- If you change issuer or subject format, treat it as a brand-new identity and re-grant access
- Never copy identity values between tokens minted under different iss/sub
When it happens
Trigger: Minting a token with an identity claim copied from an old iss/sub pair, then changing the issuer or subject (URL change, provider migration, casing/format tweak changes the hash) without recomputing identity; hand-assembled tokens with a stale identity field.
Common situations: Re-issuing tokens under a new issuer URL while reusing the old identity claim; token tooling that hardcodes an identity value; provider changing subject formatting after an upgrade.
Related errors
- Issuer too long: {:?}
- Subject too long: {:?}
- Issuer empty
- Subject empty
- No fingerprint saved for server: {}
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/46b3daf4dc9392c9.
Report an issue: GitHub.