clockworklabs/SpacetimeDB · error
Procedure `{name}` not found
Error message
Procedure `{name}` not found What it means
The procedure counterpart of the reducer lookup: function_to_procedure_call_params resolves the requested name via procedure_by_name_with_module in the deployed module's definition. If no procedure with that name exists, scheduling aborts with this error before arguments are deserialized (argument mismatches instead produce InvalidProcedureArguments).
Source
Thrown at crates/core/src/host/scheduler.rs:858
return Err(anyhow!("Reducer `{name}` not found"));
};
let args = args.into_tuple_for_def(owning, def).map_err(InvalidReducerArguments)?;
let (ts, instant) = scheduled_call_time(at);
Ok((ts, instant, CallReducerParams::from_system(ts, identity, id, args)))
}
fn function_to_procedure_call_params(
module: &ModuleInfo,
name: &str,
args: FunctionArgs,
at: Option<Timestamp>,
) -> anyhow::Result<(Timestamp, Instant, CallProcedureParams)> {
let identity = module.database_identity;
let module = &module.module_def;
let Some((id, def, owning)) = module.procedure_by_name_with_module(name) else {
return Err(anyhow!("Procedure `{name}` not found"));
};
let args = args
.into_tuple_for_def(owning, def)
.map_err(InvalidProcedureArguments)?;
let (ts, instant) = scheduled_call_time(at);
Ok((ts, instant, CallProcedureParams::from_system(ts, identity, id, args)))
}
fn scheduled_call_time(at: Option<Timestamp>) -> (Timestamp, Instant) {
// The timestamp we tell the function it's running at will be
// at least the timestamp it was scheduled to run at.
let now = Timestamp::now();
let ts = at.unwrap_or(now).max(now);
let instant = Instant::now() + ts.duration_since(now).unwrap_or(Duration::ZERO);
(ts, instant)
}
View on GitHub (pinned to 524b4487d9)
Solutions
- Look up the deployed module's procedure list and use the exact current canonical name.
- Remove or migrate schedule entries that reference renamed or deleted procedures in the same release.
- Redeploy the module revision containing the requested procedure.
- Add a post-publish check that every scheduled procedure name resolves in the new module definition.
Example fix
// before: schedule references a procedure name that no longer exists
schedule_procedure("nightlyRefresh", args, None)?;
// after: name matches the deployed module_def
schedule_procedure("nightly_refresh", args, None)?; Defensive patterns
Strategy: validation
Validate before calling
// Validate the name against the deployed module before scheduling
let known: HashSet<_> = module_def.procedure_names().collect();
anyhow::ensure!(known.contains(name), "procedure {name} not in deployed module"); Try / catch
let err = schedule_procedure_call(...).unwrap_err();
if err.to_string().starts_with("Procedure `") {
// name-resolution failure — fix configuration or redeploy, do not retry
} Prevention
- Keep schedule entries in sync with the deployed procedure list.
- Migrate or drop schedules referencing renamed or deleted procedures in the same release.
- Smoke-test every scheduled procedure name after each publish.
When it happens
Trigger: Scheduling a procedure by a name that module_def does not contain: stale schedule entries referencing a deleted or renamed procedure, a typo'd name, or a client built against a newer module revision whose procedures are not yet deployed.
Common situations: Renaming or removing procedures between publishes without cleaning up schedules; version skew between client code and the deployed module; moving procedures between submodules changing their canonical names.
Related errors
- Reducer `{name}` not found
- transaction retry failed again
- unknown procedureId ${id}
- scheduled table {table_id} doesn't have valid columns
- Failed to convert 'scheduled_at' to ScheduleAt: {e:?}
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/bb99acad32cf0ab6.
Report an issue: GitHub.