{"record":{"id":"4cca251a8df3a639","repo":"clockworklabs/SpacetimeDB","slug":"reducer-name-not-found","errorCode":null,"errorMessage":"Reducer `{name}` not found","messagePattern":"Reducer `(.+?)` not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/host/scheduler.rs","lineNumber":840,"sourceCode":"            function_to_call_params(module, &function_name, args, None)?\n        }\n    }))\n}\n\nfn function_to_reducer_call_params(\n    module: &ModuleInfo,\n    name: &str,\n    args: FunctionArgs,\n    at: Option<Timestamp>,\n) -> anyhow::Result<(Timestamp, Instant, CallReducerParams)> {\n    let identity = module.database_identity;\n\n    // Find the reducer and deserialize the arguments.\n    // Use the owning module's typespace (not necessarily the root's) so that type-index\n    // references inside the def are resolved correctly for submodules.\n    let module = &module.module_def;\n    let Some((id, def, owning)) = module.reducer_by_name_with_module(name) else {\n        return Err(anyhow!(\"Reducer `{name}` not found\"));\n    };\n    let args = args.into_tuple_for_def(owning, def).map_err(InvalidReducerArguments)?;\n\n    let (ts, instant) = scheduled_call_time(at);\n    Ok((ts, instant, CallReducerParams::from_system(ts, identity, id, args)))\n}\n\nfn function_to_procedure_call_params(\n    module: &ModuleInfo,\n    name: &str,\n    args: FunctionArgs,\n    at: Option<Timestamp>,\n) -> anyhow::Result<(Timestamp, Instant, CallProcedureParams)> {\n    let identity = module.database_identity;\n\n    let module = &module.module_def;\n    let Some((id, def, owning)) = module.procedure_by_name_with_module(name) else {\n        return Err(anyhow!(\"Procedure `{name}` not found\"));","sourceCodeStart":822,"sourceCodeEnd":858,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/core/src/host/scheduler.rs#L822-L858","documentation":"When the scheduler converts a requested call into reducer-call parameters (function_to_reducer_call_params), it looks the name up in the deployed module's definition via reducer_by_name_with_module, resolving type references in the owning (sub)module's typespace. A miss means the module currently deployed to this database has no reducer with that name, so nothing can be scheduled; the request fails at name resolution and never reaches user code.","triggerScenarios":"Scheduling a reducer by a name absent from module_def: persisted scheduled/crontab entries from an older module after the reducer was renamed or deleted; a typo'd reducer name in a scheduling request; client or SDK code newer than the deployed module referencing reducers that do not exist yet.","commonSituations":"Renaming or removing a reducer between publishes while stale schedule entries still reference the old name; rolling back to an older module revision than scheduling code expects; submodule moves that changed a reducer's canonical name.","solutions":["Check the deployed module's reducer list (module info / generated bindings) and use the exact current name, including any submodule namespace.","If the reducer was renamed, republish keeping a thin wrapper under the old name, or clear the stale scheduled entries and re-schedule.","Redeploy the module revision that actually contains the requested reducer.","After every publish, re-verify crontab and persisted schedule entries against the new module definition."],"exampleFix":"// before: schedule references a reducer that was removed in the latest publish\nschedule(\"cleanOld\", args, None)?;\n\n// after: name matches the deployed module_def\nschedule(\"purge_expired\", args, None)?;","handlingStrategy":"validation","validationCode":"// Validate the name against the deployed module before scheduling\nlet known: HashSet<_> = module_def.reducer_names().collect();\nanyhow::ensure!(known.contains(name), \"reducer {name} not in deployed module\");","typeGuard":null,"tryCatchPattern":"let err = schedule_call(...).unwrap_err();\nif err.to_string().starts_with(\"Reducer `\") {\n    // stale schedule entry or renamed reducer — fix configuration, do not retry\n}","preventionTips":["Keep crontab and persisted schedule entries in sync with the deployed reducer list.","When renaming a reducer, remove or migrate schedules referencing the old name in the same release.","Run a smoke test that schedules every configured function after each publish."],"tags":["scheduler","reducer","name-resolution","module-def"],"backgroundTag":"function-not-found","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}