tokio-rs/axum · error · compile_error

can't infer state type, please add `#[{attr_name}(state = My

Error message

can't infer state type, please add `#[{attr_name}(state = MyStateType)]` attribute

What it means

Emitted by the `#[derive(FromRequest)]` / `#[derive(FromRequestParts)]` proc macros after the macro scans the struct's fields and finds two or more _different_ candidate state types (each `State<T>` field, or each field with `#[from_request(via(State))]`, contributes one). The macro enters the `State::CannotInfer` branch (from_request/mod.rs:129) and, at the end of expansion (line 149), emits this compile_error alongside the generated `impl`. Because a derive cannot prompt at runtime, it asks the developer to disambiguate with a container-level `#[from_request(state = MyStateType)]` attribute.

Source

Thrown at axum-macros/src/from_request/mod.rs:154

                    fields,
                    &via,
                    rejection.as_ref(),
                    generic_ident.as_ref(),
                    &state,
                    tr,
                )?,
                (None, rejection) => {
                    error_on_generic_ident(generic_ident, tr)?;
                    impl_struct_by_extracting_each_field(&ident, &fields, rejection, &state, tr)?
                }
            };

            if matches!(state, State::CannotInfer) {
                let attr_name = match tr {
                    Trait::FromRequest => "from_request",
                    Trait::FromRequestParts => "from_request_parts",
                };
                let compile_error = syn::Error::new(
                    Span::call_site(),
                    format_args!(
                        "can't infer state type, please add \
                         `#[{attr_name}(state = MyStateType)]` attribute",
                    ),
                )
                .into_compile_error();

                Ok(quote! {
                    #trait_impl
                    #compile_error
                })
            } else {
                Ok(trait_impl)
            }
        }
        syn::Item::Enum(item) => {
            let syn::ItemEnum {

View on GitHub (pinned to c9a911b799)

Solutions

  1. Add `#[from_request(state(AppState))]` (or `state = AppState`) on the struct, naming the single top-level router state; sub-states continue to come from `FromRef<AppState>`.
  2. Reduce the struct to a single `State<T>` field and derive the other values from it via `FromRef` inside a separate extractor or the handler.
  3. If the fields really do need different router states, split the struct into two extractors — `FromRequest`/`FromRequestParts` can only be implemented against one `S`.
  4. Verify the field-level `#[from_request(via(State))]` annotations; each such field contributes its own type to inference, so removing a redundant `via(State)` may collapse the set.

Example fix

// before
#[derive(FromRequest)]
struct Extractor {
    a: State<AppState>,
    b: State<One>,
}

// after
#[derive(FromRequest)]
#[from_request(state(AppState))]
struct Extractor {
    a: State<AppState>,
    b: State<One>,
}
Defensive patterns

Strategy: validation

Validate before calling

// Convention: always pair #[derive(FromRequest)] with an explicit state attribute
// on any struct that has more than one field. Add this module-level assertion
// to fail fast if someone adds a second State<T>:
//
// #[derive(FromRequest)]
// #[from_request(state(AppState))]   // <-- always present
// struct Extractor { a: State<AppState>, b: String }
//
// Static check that AppState is clone+send+sync (the bounds the derive emits):
const _: fn() = || {
    fn assert_state_bounds<S: Clone + Send + Sync>() {}
    assert_state_bounds::<AppState>();
};

Type guard

// Narrowing helper for call sites that must accept only the intended state.
pub trait FromRequestForState {}
impl FromRequestForState for crate::Extractor {}

// Then any generic API can be constrained:
pub fn run<E: FromRequestForState>(_e: E) {}
// Mis-deriving against the wrong state type breaks this impl, not the macro.

Prevention

When it happens

Trigger: A struct has multiple fields whose types resolve to distinct state inner-types, e.g. `struct E { a: State<AppState>, b: State<OtherState> }` with `#[derive(FromRequest)]` and no container `state(...)` attribute. The inference collects types via `infer_state_type_from_field_types` (line 999) plus `infer_state_type_from_field_attributes` (line 1022); when the resulting `HashSet` has >1 element the `State::CannotInfer` arm fires (line 129) and the compile_error is produced at line 154. Reproducible with the repo's own `tests/from_request/fail/state_infer_multiple_different_types.rs`.

Common situations: Building an extractor that pulls several sub-states out of a shared `AppState` (each via its own `FromRef`) but forgetting that the derive tries to infer one router-level `S`. Splitting a monolithic `AppState` into smaller sub-states and updating extractor fields one-by-one. Migration from a hand-written `impl FromRequestParts` (where the state type was explicit in the signature) to the derive, leaving the field set ambiguous.

Related errors


AI-assisted analysis of tokio-rs/axum@c9a911b799 (2026-08-06). Data as JSON: /data/errors/9ffef49e686975b0.json. Report an issue: GitHub.