{"id":"9ffef49e686975b0","repo":"tokio-rs/axum","slug":"can-t-infer-state-type-please-add-attr-name","errorCode":null,"errorMessage":"can't infer state type, please add `#[{attr_name}(state = MyStateType)]` attribute","messagePattern":"can't infer state type, please add `#\\[(.+?)\\(state = MyStateType\\)\\]` attribute","errorType":"validation","errorClass":"compile_error","httpStatus":null,"severity":"error","filePath":"axum-macros/src/from_request/mod.rs","lineNumber":154,"sourceCode":"                    fields,\n                    &via,\n                    rejection.as_ref(),\n                    generic_ident.as_ref(),\n                    &state,\n                    tr,\n                )?,\n                (None, rejection) => {\n                    error_on_generic_ident(generic_ident, tr)?;\n                    impl_struct_by_extracting_each_field(&ident, &fields, rejection, &state, tr)?\n                }\n            };\n\n            if matches!(state, State::CannotInfer) {\n                let attr_name = match tr {\n                    Trait::FromRequest => \"from_request\",\n                    Trait::FromRequestParts => \"from_request_parts\",\n                };\n                let compile_error = syn::Error::new(\n                    Span::call_site(),\n                    format_args!(\n                        \"can't infer state type, please add \\\n                         `#[{attr_name}(state = MyStateType)]` attribute\",\n                    ),\n                )\n                .into_compile_error();\n\n                Ok(quote! {\n                    #trait_impl\n                    #compile_error\n                })\n            } else {\n                Ok(trait_impl)\n            }\n        }\n        syn::Item::Enum(item) => {\n            let syn::ItemEnum {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/tokio-rs/axum/blob/c9a911b7999de50e9e5023942ca072e9725ae943/axum-macros/src/from_request/mod.rs#L136-L172","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["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>`.","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.","If the fields really do need different router states, split the struct into two extractors — `FromRequest`/`FromRequestParts` can only be implemented against one `S`.","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."],"exampleFix":"// before\n#[derive(FromRequest)]\nstruct Extractor {\n    a: State<AppState>,\n    b: State<One>,\n}\n\n// after\n#[derive(FromRequest)]\n#[from_request(state(AppState))]\nstruct Extractor {\n    a: State<AppState>,\n    b: State<One>,\n}","handlingStrategy":"validation","validationCode":"// Convention: always pair #[derive(FromRequest)] with an explicit state attribute\n// on any struct that has more than one field. Add this module-level assertion\n// to fail fast if someone adds a second State<T>:\n//\n// #[derive(FromRequest)]\n// #[from_request(state(AppState))]   // <-- always present\n// struct Extractor { a: State<AppState>, b: String }\n//\n// Static check that AppState is clone+send+sync (the bounds the derive emits):\nconst _: fn() = || {\n    fn assert_state_bounds<S: Clone + Send + Sync>() {}\n    assert_state_bounds::<AppState>();\n};","typeGuard":"// Narrowing helper for call sites that must accept only the intended state.\npub trait FromRequestForState {}\nimpl FromRequestForState for crate::Extractor {}\n\n// Then any generic API can be constrained:\npub fn run<E: FromRequestForState>(_e: E) {}\n// Mis-deriving against the wrong state type breaks this impl, not the macro.","tryCatchPattern":null,"preventionTips":["Always annotate multi-field extractors with `#[from_request(state(...))]` even if inference currently succeeds; future field additions won't break the build.","Centralize router state in one `AppState` and expose sub-states through `FromRef` so all `State<T>` fields share the same inference target.","During code review, flag any `#[derive(FromRequest)]` on a struct with >1 `State<T>` field that lacks an explicit `state(...)`.","Keep the repo's `tests/from_request/fail/state_infer_multiple_different_types.rs` pattern in mind as the canonical anti-example."],"tags":["rust","axum","proc-macro","from-request","state-inference","derive","compile-time"],"analyzedSha":"c9a911b7999de50e9e5023942ca072e9725ae943","analyzedAt":"2026-08-06T01:08:56.656Z","schemaVersion":2}