clockworklabs/SpacetimeDB · error
Error getting jwt: {errno}
Error message
Error getting jwt: {errno} What it means
bindings-sys get_jwt panics when the host returns an errno for the get_jwt syscall instead of a payload. Per the raw ABI the only documented errno is NOT_IN_TRANSACTION: reading the JWT touches a system table, so it must run inside a transaction (i.e. inside a reducer call). A connection with no JWT is NOT an error - that case returns None (INVALID BytesSource).
Source
Thrown at crates/bindings-sys/src/lib.rs:1486
raw::identity(buf.as_mut_ptr());
}
buf
}
/// Finds the JWT payload associated with `connection_id`.
/// If nothing is found for the connection, this returns None.
/// If a payload is found, this will return a valid [`raw::BytesSource`].
///
/// This must be called inside a transaction (because it reads from a system table).
///
/// # Errors
///
/// This panics on any error. You can see details about errors in [`raw::get_jwt`].
#[inline]
pub fn get_jwt(connection_id: [u8; 16]) -> Option<raw::BytesSource> {
let source = unsafe {
call(|out| raw::get_jwt(connection_id.as_ptr(), out))
.unwrap_or_else(|errno: Errno| panic!("Error getting jwt: {errno}"))
};
if source == raw::BytesSource::INVALID {
None // No JWT found.
} else {
Some(source)
}
}
pub struct RowIter {
raw: raw::RowIter,
}
impl RowIter {
/// Read some number of BSATN-encoded rows into the provided buffer.
///
/// Returns the number of new bytes added to the end of the buffer.
/// When the iterator has been exhausted,View on GitHub (pinned to 6dee26c6ef)
Solutions
- Move the get_jwt call inside a #[reducer] function - reducers always run in a transaction.
- Take the connection id from the current call's ReducerContext (ctx.connection_id()) rather than storing one from an earlier invocation.
- Handle the None return for connections that did not authenticate with a JWT instead of assuming a payload.
Example fix
// before: called outside a transaction
fn maybe_forward(ctx_id: ConnectionId) {
let jwt = spacetimedb::get_jwt(ctx_id); // panics: NOT_IN_TRANSACTION
}
// after: inside a reducer, using the live context
#[spacetimedb::reducer]
fn forward_jwt(ctx: &ReducerContext) {
if let Some(jwt) = spacetimedb::get_jwt(ctx.connection_id()) {
// use jwt payload
}
} Defensive patterns
Strategy: validation
Prevention
- Only call get_jwt inside a #[reducer] - reducers are the only context with a transaction.
- Always source the ConnectionId from ReducerContext::connection_id() of the current call, never a stored one.
- Treat None as a normal result: not every connection authenticated with a JWT.
When it happens
Trigger: Calling get_jwt(connection_id) outside a reducer transaction, e.g. from an HTTP handler, from module initialization code, or from a helper invoked after the reducer's transaction ended; using a ConnectionId captured in a previous call.
Common situations: Refactoring external-authentication forwarding (calling a third-party API with the caller's JWT) out of a reducer into an HTTP handler; testing JWT plumbing in a plain unit function rather than a reducer.
Related errors
- {errno}
- unexpected error from `_row_iter_bsatn_advance`: {e}
- Unexpected type for 'aud' claim in JWT
- wasm32-unknown-unknown target is not installed. Please insta
- Found {err_count} disallowed print statement(s). These will
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/081af807d3dc5a73.
Report an issue: GitHub.