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

  1. Look up the deployed module's procedure list and use the exact current canonical name.
  2. Remove or migrate schedule entries that reference renamed or deleted procedures in the same release.
  3. Redeploy the module revision containing the requested procedure.
  4. 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

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


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/bb99acad32cf0ab6. Report an issue: GitHub.