databendlabs/databend · error

Failed to register spawn function

Error message

Failed to register spawn function: {}

What it means

After the `spawn` function is created it is stored in the `metactl` table with `Table::set`. mlua's `set` serializes the key/value into Lua; if that fails (Lua stack exhaustion, memory error, or a value that cannot be pushed), the error is wrapped as `Failed to register spawn function` and setup aborts.

Solutions

  1. Inspect the inner mlua error; memory/stack errors usually mean the Lua state should be recreated rather than reused.
  2. Confirm `metactl_table` was created in the same Lua instance as `spawn_fn`; cross-instance values fail to push.
  3. Raise or remove any custom Lua memory limit (MemoryLimits) if the inner error is MemoryError.
  4. Retry in a fresh environment; if reproducible, file against mlua with the inner error text.
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = setup_lua_environment(&lua) {
    if e.to_string().contains("Failed to register spawn function") {
        // rebuild Lua state / surface inner mlua error to the operator
    }
}

Prevention

When it happens

Trigger: `metactl_table.set("spawn", spawn_fn)` returning an mlua::Error during `setup_lua_environment`, i.e. during any `run_lua_script`/`run_lua_script_with_result` call or the associated tests.

Common situations: Lua state stack/memory exhaustion from a prior runaway script, or running in an mlua build where function values cannot be stored (sandboxed/limited runtime).

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/51535e8b83e39e8e. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/control/src/lua_support.rs:449

            let handle = tokio::task::spawn_local(async move {
                match func.call_async::<mlua::Value>(()).await {
                    Ok(result) => result,
                    Err(e) => {
                        eprintln!("Spawned task error: {}", e);
                        mlua::Value::Nil
                    }
                }
            });

            Ok(LuaTask {
                handle: Rc::new(RefCell::new(Some(handle))),
            })
        })
        .map_err(|e| anyhow::anyhow!("Failed to create spawn function: {}", e))?;

    metactl_table
        .set("spawn", spawn_fn)
        .map_err(|e| anyhow::anyhow!("Failed to register spawn function: {}", e))?;

    // Register async sleep function
    let sleep_fn = lua
        .create_async_function(|_lua, seconds: f64| async move {
            let duration = duration_from_seconds(seconds, "sleep")?;
            time::sleep(duration).await;
            Ok(())
        })
        .map_err(|e| anyhow::anyhow!("Failed to create sleep function: {}", e))?;

    metactl_table
        .set("sleep", sleep_fn)
        .map_err(|e| anyhow::anyhow!("Failed to register sleep function: {}", e))?;

    // Register a monotonic millisecond clock for timing and benchmarks. The
    // epoch is this environment's setup time; only differences between calls are
    // meaningful. `Instant` guarantees the value never goes backwards.
    let start = std::time::Instant::now();

View on GitHub (pinned to 288d84d76e)