hasura/graphql-engine · error · Error
Unexpected value: expecting {expected_kind:}, but found: {fo
Error message
Unexpected value: expecting {expected_kind:}, but found: {found:} What it means
The IR (intermediate representation) layer throws this when it encounters a JSON value whose kind doesn't match what the IR constructor expected at that position — e.g. a string where an object is required, or an array where a scalar is expected. The message names the expected kind and echoes the offending value, making it a structural validation error on incoming request data.
Source
Thrown at v3/crates/graphql/ir/src/error.rs:46
}
}
}
}
#[allow(clippy::duplicated_attributes)] // suppress spurious warnings from Clippy
#[derive(Error, Debug, Transitive)]
#[transitive(from(json::Error, InternalError))]
#[transitive(from(gql::normalized_ast::Error, InternalError))]
#[transitive(from(InternalEngineError, InternalError))]
#[transitive(from(InternalDeveloperError, InternalError))]
pub enum Error {
#[error("The global ID {encoded_value:} couldn't be decoded due to {decoding_error:}")]
FailureDecodingGlobalId {
encoded_value: String,
decoding_error: String,
},
#[error("Unexpected value: expecting {expected_kind:}, but found: {found:}")]
UnexpectedValue {
expected_kind: &'static str,
found: json::Value,
},
#[error("'{name:}' is not a valid GraphQL name.")]
TypeFieldInvalidGraphQlName { name: String },
#[error("'{alias:} is not a valid alias")]
InvalidAlias { alias: String },
#[error("{value} is not a valid limit value")]
InvalidLimitValue { value: u32 },
#[error("{value} is not a valid offset value")]
InvalidOffsetValue { value: u32 },
#[error("field '{field_name:} not found in entity representation")]View on GitHub (pinned to 724551b9ae)
Solutions
- Inspect the 'found' value in the error and compare with the documented expected type for that argument/field
- Fix the client to send correctly typed JSON (e.g. 42 not "42")
- Add client-side schema validation (codegen, zod, etc.) so variables are type-checked before sending
Example fix
// before
variables: {{ filter: {{ count: "10" }} }}
// after
variables: {{ filter: {{ count: 10 }} }} Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof variables.filter?.count !== 'number') {
throw new TypeError('filter.count must be a number');
} Type guard
function isRecord(v: unknown): v is Record<string, unknown> {{
return typeof v === 'object' && v !== null && !Array.isArray(v);
}} Try / catch
try {{
await execute(query, variables);
}} catch (e: any) {{
if (e.message.includes('Unexpected value: expecting')) {{
// log variables, fix types, retry
}}
}} Prevention
- Use generated types (graphql-codegen) for variables
- Validate variable payloads with zod/io-ts before sending
- Avoid coercing all values to strings in HTTP layers
When it happens
Trigger: Building IR values from request JSON: a where-clause argument, variable default, or entity representation field receives a JSON value of the wrong type (string given where number/object was expected).
Common situations: Clients sending loosely-typed variables (numbers as strings); schema/serialization drift between what the client sends and what the IR builder expects; hand-crafted JSON requests bypassing generated types.
Related errors
- validation failed: {0}
- Unable to parse WebSocket message: {0}
- '{name:}' is not a valid GraphQL name.
- '{alias:} is not a valid alias
- {value} is not a valid limit value
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/abf152f0c6d6d428.
Report an issue: GitHub.