hasura/graphql-engine · error · Error
Expected string value for claim {claim_name}
Error message
Expected string value for claim {claim_name} What it means
The claims map indicates a claim should be a string (or a string is required for further processing), but the JWT contains a non-string value (object, number, array, boolean) for that claim.
Source
Thrown at v3/crates/auth/hasura-authn-jwt/src/jwt.rs:44
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Error decoding the `Authorization` header - {0}")]
ErrorDecodingAuthorizationHeader(jwt::errors::Error),
#[error("`kid` (Key ID) header claim not found in the header")]
KidHeaderNotFound,
#[error("Expected the Hasura claims to be a String when `claimsFormat` is `stringifiedJson`")]
ExpectedStringifiedJson,
#[error("The default role is not present in the allowed roles")]
DisallowedDefaultRole,
#[error("The specified role is not present in the allowed roles")]
DisallowedRole,
#[error("Error while parsing the claims map entry: {claim_name} - {err}")]
ParseClaimsMapEntryError {
claim_name: String,
err: serde_json::Error,
},
#[error("Expected string value for claim {claim_name}")]
ClaimMustBeAString { claim_name: String },
#[error("Required claim {claim_name} not found")]
RequiredClaimNotFound { claim_name: String },
#[error("JWT Authorization token source: Header name {header_name} not found.")]
AuthorizationHeaderSourceNotFound { header_name: String },
#[error("JWT Authorization token source: Cookie header not found")]
CookieNotFound,
#[error(
"JWT Authorization token source: cookie name {cookie_name} not found in the Cookie header"
)]
CookieNameNotFound { cookie_name: String },
#[error("Error in parsing the {header_name} header: {err}")]
AuthorizationHeaderParseError { err: String, header_name: String },
#[error("Error in parsing the Cookie header value: {err}")]
CookieParseError { err: cookie::ParseError },
#[error("Missing corresponding value for the cookie with cookie name: {cookie_name}")]
MissingCookieValue { cookie_name: String },
#[error("JWT validation error: {0}")]View on GitHub (pinned to 724551b9ae)
Solutions
- Decode the token and check the JSON type of {claim_name}
- Ensure the token issuer emits the claim as a string (e.g. quote roles/IDs in the JWT payload)
- Adjust the claims map configuration to point at a claim that is actually a string
Example fix
// before (JWT payload)
{ "https://hasura.io/jwt/claims": { "default-role": "user", "x-claim": 123 } }
// after
{ "https://hasura.io/jwt/claims": { "default-role": "user", "x-claim": "123" } } Defensive patterns
Strategy: type-guard
Validate before calling
const payload = decodeJwt(token);
for (const name of requiredStringClaims) {
if (typeof payload[name] !== 'string') return reject('claim ' + name + ' must be a string');
} Type guard
const isString = (v: unknown): v is string => typeof v === 'string';
Try / catch
Map the error to a 401 with a message naming the offending claim; prompt token refresh.
Prevention
- Ensure the IdP custom-claims template emits strings (quote numbers)
- Add contract tests on issued tokens
When it happens
Trigger: Extracting Hasura roles or other configured claims where the configured claim path resolves to a non-string JSON value, e.g. `"default-role": 42` instead of `"default-role": "user"`.
Common situations: Auth provider issues numeric or structured claims where strings are expected; metadata config assumes a string type that the IdP does not emit.
Related errors
- Error while parsing the claims map entry: {claim_name} - {er
- Required claim {claim_name} not found
- Session variable not found: {name}
- Expected array or null for right-hand value of contains oper
- Expected number for {side}-hand value of comparison operatio
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/8d759b7e78daa1b6.
Report an issue: GitHub.