{"record":{"id":"f9b79f11c5dda115","repo":"clockworklabs/SpacetimeDB","slug":"subject-too-long","errorCode":null,"errorMessage":"Subject too long: {:?}","messagePattern":"Subject too long: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/auth/src/identity.rs","lineNumber":111,"sourceCode":"    #[serde_as(as = \"Option<serde_with::TimestampSeconds>\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub exp: Option<SystemTime>,\n\n    /// All remaining claims from the JWT payload\n    #[serde(flatten)]\n    pub extra: Option<HashMap<Box<str>, serde_json::Value>>,\n}\n\nimpl TryInto<SpacetimeIdentityClaims> for IncomingClaims {\n    type Error = anyhow::Error;\n\n    fn try_into(self) -> anyhow::Result<SpacetimeIdentityClaims> {\n        // The issuer and subject must be less than 128 bytes.\n        if self.issuer.len() > 128 {\n            return Err(anyhow::anyhow!(\"Issuer too long: {:?}\", self.issuer));\n        }\n        if self.subject.len() > 128 {\n            return Err(anyhow::anyhow!(\"Subject too long: {:?}\", self.subject));\n        }\n        // The issuer and subject must be non-empty.\n        if self.issuer.is_empty() {\n            return Err(anyhow::anyhow!(\"Issuer empty\"));\n        }\n        if self.subject.is_empty() {\n            return Err(anyhow::anyhow!(\"Subject empty\"));\n        }\n\n        let computed_identity = Identity::from_claims(&self.issuer, &self.subject);\n        // If an identity is provided, it must match the computed identity.\n        if let Some(token_identity) = self.identity\n            && token_identity != computed_identity\n        {\n            return Err(anyhow::anyhow!(\n                    \"Identity mismatch: token identity {token_identity:?} does not match computed identity {computed_identity:?}\",\n                ));\n        }","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/3653d2ed498fddbd83b7062aa6bf8970e18635ec/crates/auth/src/identity.rs#L93-L129","documentation":"The same IncomingClaims -> SpacetimeIdentityClaims conversion enforces a 128-byte cap on the `sub` claim (crates/auth/src/identity.rs:106). Subject and issuer are hashed together into the Identity, so both are bounded. An oversized subject is rejected with its debug form in the message.","triggerScenarios":"Authenticating with a JWT whose `sub` exceeds 128 bytes - e.g. providers that emit composite subjects (user-id + tenant + session concatenated), full UUID URNs with long prefixes, or identifiers carrying encoded metadata.","commonSituations":"Enterprise IdPs with verbose subject formats; token services that encode scopes or tenant info into sub instead of separate claims; testing with synthetic oversized identifiers.","solutions":["Configure the provider/token service to emit a compact subject (opaque user id) and move extra data to other claims.","If subjects are fixed by the provider, introduce a token-exchange step that rewrites sub to a short id before the token reaches SpacetimeDB.","Reissue tokens after the change; identities derived from the old subject will not match the new ones."],"exampleFix":"// before\n{ \"iss\": \"https://app.example.com\", \"sub\": \"urn:example:tenant:1234567890:user:abcdef01-2345-6789-abcd-ef0123456789:session:...\" }\n// after\n{ \"iss\": \"https://app.example.com\", \"sub\": \"user_abcdef01\", \"tid\": \"1234567890\" }","handlingStrategy":"validation","validationCode":"// Rust: validate subject size before converting.\nif claims.subject.len() > 128 {\n    return Err(anyhow!(\"sub too long ({} bytes, max 128); use a compact subject id\", claims.subject.len()));\n}","typeGuard":"fn subject_within_limit(c: &IncomingClaims) -> bool {\n    (1..=128).contains(&c.subject.len())\n}","tryCatchPattern":null,"preventionTips":["Emit opaque short subject ids from your identity provider or token exchange.","Never encode composite metadata (tenant + session + scopes) into sub; use separate claims.","Log claim sizes (not values) at issuance in CI to catch provider format changes early."],"tags":["spacetimedb","auth","jwt","identity","claims-validation"],"backgroundTag":"jwt-claims-validation","analyzedSha":"3653d2ed498fddbd83b7062aa6bf8970e18635ec","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}