denoland/deno · error · Error
startActiveSpan requires a function argument
Error message
startActiveSpan requires a function argument
What it means
Thrown by Tracer.startActiveSpan() in Deno's built-in OpenTelemetry shim (ext/telemetry/telemetry.ts:374). The method resolves its argument overloads (name, fn), (name, options, fn), or (name, options, context, fn); if none of the second, third, or fourth argument is a function, it throws this Error. This mirrors @opentelemetry/api semantics where the span is only active for the duration of the synchronous callback.
Source
Thrown at ext/telemetry/telemetry.ts:396
optionsOrFn: SpanOptions | F,
fnOrContext?: F | Context,
maybeFn?: F,
) {
let options;
let context;
let fn;
if (typeof optionsOrFn === "function") {
options = undefined;
fn = optionsOrFn;
} else if (typeof fnOrContext === "function") {
options = optionsOrFn;
fn = fnOrContext;
} else if (typeof maybeFn === "function") {
options = optionsOrFn;
context = fnOrContext;
fn = maybeFn;
} else {
throw new Error("startActiveSpan requires a function argument");
}
if (options?.root) {
context = ROOT_CONTEXT;
} else {
context = context ?? CURRENT.get() ?? ROOT_CONTEXT;
}
const span = this.startSpan(name, options, context);
const ctx = CURRENT.enter(context.setValue(SPAN_KEY, span));
try {
return ReflectApply(fn, undefined, [span]);
} finally {
setAsyncContext(ctx);
}
}
startSpan(name: string, options?: SpanOptions, context?: Context): Span {
if (options?.root) {
context = undefined;View on GitHub (pinned to a961cdec3b)
Solutions
- Pass the callback as the second argument: tracer.startActiveSpan(name, (span) => { ... })
- If you need options, put them before the callback: tracer.startActiveSpan(name, { attributes }, (span) => { ... })
- If the callback comes from a variable, guard with typeof fn === 'function' before calling
- If you do not want an active-context callback, use tracer.startSpan(name, options, context) and end the span yourself
Example fix
// before
tracer.startActiveSpan("fetch", { attributes: { url } });
// after
tracer.startActiveSpan("fetch", { attributes: { url } }, (span) => {
try {
return doFetch(url);
} finally {
span.end();
}
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof fn !== "function") {
throw new TypeError("startActiveSpan requires a function argument");
}
tracer.startActiveSpan(name, options, fn); Type guard
function isSpanCallback(
v: unknown,
): v is (span: unknown) => unknown {
return typeof v === "function";
} Try / catch
try {
tracer.startActiveSpan(name, options, fn);
} catch (e) {
if (e instanceof Error && e.message.includes("requires a function argument")) {
// fall back to a manual span
const span = tracer.startSpan(name, options);
span.end();
} else {
throw e;
}
} Prevention
- Type the call site against @opentelemetry/api overloads so TypeScript rejects missing callbacks
- Enable strict TypeScript (noImplicitAny, strictBindCallApply) so wrong-arity calls surface
- Never pass optionally-defined callbacks; assert or default them first
When it happens
Trigger: tracer.startActiveSpan('fetch') with no callback; tracer.startActiveSpan('fetch', { attributes: {...} }) with options but the callback forgotten; the fn variable being conditionally undefined at the call site (e.g. fn loaded from config); swapping the context and fn arguments so no checked position holds a function.
Common situations: Porting manual span code written with startSpan to startActiveSpan and forgetting the callback; refactors that extract the inline closure into a variable that can be undefined; JS code without TypeScript overloads catching the mistake at compile time.
Related errors
- TracerProvider can not be constructed
- ContextManager can not be constructed
- MeterProvider can not be constructed
- Only valueType: DOUBLE is supported
- Failed to inject with ${propagator.constructor.name}.
AI-assisted analysis of denoland/deno@a961cdec3b (2026-08-20).
Data as JSON: /api/errors/6707a461fad3c471.
Report an issue: GitHub.