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

  1. 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
  2. Unset the variable entirely (Deno then defaults to sampling every span, i.e. always_on behavior)
  3. If you wanted probabilistic sampling, use traceidratio plus OTEL_TRACES_SAMPLER_ARG=0.25 (a number in [0,1])
  4. 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

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


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)