n8n-io/n8n · error · Error
OpenTelemetry active span callback is required.
Error message
OpenTelemetry active span callback is required.
What it means
Thrown by MetadataEnrichedTracer.startActiveSpan when the call resolves optionsOrFn to a SpanOptions object but neither contextOrFn nor fn is a function — i.e. the caller invoked the three-or-four-arg overload without supplying the required active-span callback. The OpenTelemetry Tracer contract requires the callback so the span can be activated around its execution.
Source
Thrown at packages/@n8n/agents/src/sdk/metadata-enriched-tracer.ts:52
startActiveSpan<F extends (span: Span) => unknown>(
name: string,
optionsOrFn: SpanOptions | F,
contextOrFn?: Context | F,
fn?: F,
): ReturnType<F> {
if (typeof optionsOrFn === 'function') {
return this.delegate.startActiveSpan(name, optionsOrFn);
}
const options = {
...optionsOrFn,
attributes: { ...this.attributes, ...optionsOrFn.attributes },
};
if (typeof contextOrFn === 'function') {
return this.delegate.startActiveSpan(name, options, contextOrFn);
}
if (contextOrFn === undefined || fn === undefined) {
throw new Error('OpenTelemetry active span callback is required.');
}
return this.delegate.startActiveSpan(name, options, contextOrFn, fn);
}
}
export function createMetadataEnrichedTracer(
tracer: Tracer,
metadata: Record<string, AttributeValue> | undefined,
): Tracer {
if (!metadata || Object.keys(metadata).length === 0) return tracer;
const attributes = Object.fromEntries(
Object.entries(metadata).map(([key, value]) => [`ai.telemetry.metadata.${key}`, value]),
);
return new MetadataEnrichedTracer(tracer, attributes);
}
View on GitHub (pinned to 5ac6606e81)
Solutions
- Always pass the callback as the final argument: startActiveSpan(name, opts, fn) or startActiveSpan(name, opts, context, fn).
- When forwarding variadic args, normalize to one of the documented overload shapes before delegating.
- Avoid as-casts on the Tracer; let TypeScript enforce the overload.
Example fix
// before
(tracer as any).startActiveSpan('span', { attributes });
// after
tracer.startActiveSpan('span', { attributes }, (span) => {
try { /* work */ } finally { span.end(); }
}); Defensive patterns
Strategy: validation
Validate before calling
function assertActiveSpanCallback(args: unknown[]) {
const last = args[args.length - 1];
if (typeof last !== 'function') {
throw new TypeError('startActiveSpan requires a callback as the final argument');
}
} Type guard
function hasSpanCallback(args: unknown[]): boolean {
return typeof args[args.length - 1] === 'function';
} Prevention
- Always invoke startActiveSpan with the callback in the final position.
- Avoid `as any` on the Tracer interface; keep the overload signatures enforcing the callback.
- When forwarding variadic args in a wrapper, normalize to (name, opts, fn) before delegating.
When it happens
Trigger: Only reachable when startActiveSpan is called with (name, SpanOptions, Context | undefined, undefined) — i.e. the callback argument is missing while earlier args are objects. Through typed TypeScript the overload signatures forbid this; it surfaces from JS callers, any/unknown-typed call sites, or as-casts that defeat the overloads.
Common situations: Third-party telemetry adapters forwarding variadic args into startActiveSpan; reflection-based tracer wrappers that drop the callback; misuse via cast (tracer as any).startActiveSpan(name, opts, ctx).
Related errors
- Telemetry tracer must implement startSpan() and startActiveS
- Cannot set both .tracer() and .otlpEndpoint() — use one or t
- Bad Gateway
- Failed to fetch source config: ${response.statusMessage}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/a5ba71a34e3be156.
Report an issue: GitHub.