denoland/deno · error · anyhow::Error
Env var OTEL_TRACES_SAMPLER specifies an unsupported sampler
Error message
Env var OTEL_TRACES_SAMPLER specifies an unsupported sampler: {} What it means
Deno's OpenTelemetry integration reads OTEL_TRACES_SAMPLER when telemetry is enabled (e.g. `deno run --otel`). The value is matched (case-sensitively, after trimming whitespace) against the six sampler names from the OTel SDK environment-variable spec: always_on, always_off, traceidratio, parentbased_always_on, parentbased_always_off, parentbased_traceidratio. Any other string aborts telemetry initialization with this anyhow error.
Solutions
- Set OTEL_TRACES_SAMPLER to one of the six exact lowercase values: always_on, always_off, traceidratio, parentbased_always_on, parentbased_always_off, parentbased_traceidratio
- Unset the variable entirely (Deno then defaults to sampling every span, i.e. always_on behavior)
- If you wanted probabilistic sampling, use traceidratio plus OTEL_TRACES_SAMPLER_ARG=0.25 (a number in [0,1])
- Print the raw value (e.g. `env | grep OTEL_TRACES`) to spot casing/typo/invisible-character problems from copied config
Example fix
# before export OTEL_TRACES_SAMPLER=ParentBased_AlwaysOn # -> unsupported sampler deno run --otel app.ts # after export OTEL_TRACES_SAMPLER=parentbased_always_on deno run --otel app.ts
Defensive patterns
Strategy: validation
Validate before calling
// Validate before launching `deno run --otel`
const ALLOWED_SAMPLERS = new Set([
"always_on", "always_off", "traceidratio",
"parentbased_always_on", "parentbased_always_off", "parentbased_traceidratio",
]);
const raw = Deno.env.get("OTEL_TRACES_SAMPLER");
const v = raw?.trim();
if (v && !ALLOWED_SAMPLERS.has(v)) {
throw new Error(`OTEL_TRACES_SAMPLER='${raw}' is not one of: ${[...ALLOWED_SAMPLERS].join(", ")}`);
} Try / catch
// Startup aborts the process; catch at the spawn layer
const cmd = new Deno.Command("deno", { args: ["run", "--otel", "app.ts"], env });
const { code, stderr } = await cmd.output();
if (code !== 0 && new TextDecoder().decode(stderr).includes("unsupported sampler")) {
// fix env and relaunch with OTEL_TRACES_SAMPLER=parentbased_always_on
} Prevention
- Keep OTel env values in one validated config module or .env file that a preflight check parses
- Use exact lowercase snake_case values from the OTel SDK env-var spec
- Add a CI step that greps OTEL_* vars against the allow-list before deploy
When it happens
Trigger: Running with --otel while OTEL_TRACES_SAMPLER is set to a non-spec value: 'AlwaysOn' (wrong case), 'parentbased_jaeger_remote' or 'traceidratiobased' (samplers other SDKs support), 'parentbased_traceidratio ' handled but 'parentbased-traceidratio' (hyphen typo) is not.
Common situations: Copying .env files from other OTel distributions (Jaeger remote sampler, X-Ray sampler); capitalizing the value because the OTel docs show mixed case in prose; trailing whitespace is tolerated but internal case is not; CI pipelines injecting sampler config via secrets managers that mangle values.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
Related errors
- Env var OTEL_EXPORTER_OTLP_PROTOCOL specifies an…
- Failed to read env var OTEL_EXPORTER_OTLP_PROTOCOL
- Invalid value for…
- must be unset or set to 1
- failed to set otel globals
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/a8912e8eb4e57a25.
Report an issue: GitHub.
Appendix: source
Thrown at ext/telemetry/lib.rs:1175
},
"traceidratio" => Sampler {
parent_based: false,
root: RootSampler::TraceIdRatio(ratio()),
},
"parentbased_always_on" => Sampler {
parent_based: true,
root: RootSampler::AlwaysOn,
},
"parentbased_always_off" => Sampler {
parent_based: true,
root: RootSampler::AlwaysOff,
},
"parentbased_traceidratio" => Sampler {
parent_based: true,
root: RootSampler::TraceIdRatio(ratio()),
},
other => {
return Err(deno_core::anyhow::anyhow!(
"Env var OTEL_TRACES_SAMPLER specifies an unsupported sampler: {}",
other
));
}
};
Ok(sampler)
}
/// Returns whether a span with the given `trace_id` should be sampled
/// (recorded and exported), given its `parent` span context if any.
fn should_sample(
&self,
parent: Option<&SpanContext>,
trace_id: TraceId,
) -> bool {
let parent_decision = parent.and_then(|parent| {
(self.parent_based && parent.is_valid()).then(|| parent.is_sampled())
});View on GitHub (pinned to 9ad36f7a2c)