Description:
Empty OTEL_TRACES_SAMPLER and OTEL_TRACES_SAMPLER_ARG values are not treated the same way as unset values in sdk/trace.
On current main, the SDK still falls back to the effective default sampler behavior, but it also emits configuration errors for empty values:
OTEL_TRACES_SAMPLER="" logs unsupported sampler:
OTEL_TRACES_SAMPLER_ARG="" with OTEL_TRACES_SAMPLER=traceidratio logs a parse error for the empty string
This appears to violate the environment variable spec requirement that empty values be interpreted the same way as unset values.
Steps to Reproduce:
- Check out
main at b34ee26cf3ea1c56e86f1e546d19c3aea5ded379.
- From WSL in the repository root, run:
repo=$(pwd)
root=/tmp/otel-empty-sampler-repro
rm -rf "$root"
mkdir -p "$root"
cat >"$root/go.mod" <<EOF
module example.com/emptysamplerrepro
go 1.25.0
require (
go.opentelemetry.io/otel v0.0.0
go.opentelemetry.io/otel/sdk v0.0.0
)
replace go.opentelemetry.io/otel => $repo
replace go.opentelemetry.io/otel/sdk => $repo/sdk
replace go.opentelemetry.io/otel/trace => $repo/trace
replace go.opentelemetry.io/otel/metric => $repo/metric
EOF
cat >"$root/main.go" <<'EOF'
package main
import (
"fmt"
"go.opentelemetry.io/otel"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func main() {
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
fmt.Println("otel error:", err)
}))
_ = sdktrace.NewTracerProvider()
fmt.Println("done")
}
EOF
cd "$root"
go mod tidy >/dev/null
OTEL_TRACES_SAMPLER= go run .
OTEL_TRACES_SAMPLER=traceidratio OTEL_TRACES_SAMPLER_ARG= go run .
Actual Behavior:
Both runs complete, but they log configuration errors even though the env var values are empty:
otel error: unsupported sampler:
done
otel error: parsing sampler argument: strconv.ParseFloat: parsing "": invalid syntax
done
Expected Behavior:
Empty OTEL_TRACES_SAMPLER and OTEL_TRACES_SAMPLER_ARG values should be treated the same as if those variables were unset.
That means:
OTEL_TRACES_SAMPLER="" should behave like the variable is absent: no config error, default sampler behavior.
OTEL_TRACES_SAMPLER_ARG="" should behave like the variable is absent: no config error, sampler uses its unset/default argument behavior.
Notes:
Spec text at https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/ says:
- empty env values must be interpreted the same as unset values
OTEL_TRACES_SAMPLER_ARG invalid input must be ignored after logging, but empty input should first hit the empty-value rule
Current code path seems to come from sdk/trace/sampler_env.go:
os.LookupEnv is used before trimming OTEL_TRACES_SAMPLER, so an empty value still enters sampler parsing
os.LookupEnv also makes an empty OTEL_TRACES_SAMPLER_ARG count as present, so traceidratio tries to parse ""
sdk/trace/provider.go then passes those returned errors to otel.Handle
Description:
Empty
OTEL_TRACES_SAMPLERandOTEL_TRACES_SAMPLER_ARGvalues are not treated the same way as unset values insdk/trace.On current
main, the SDK still falls back to the effective default sampler behavior, but it also emits configuration errors for empty values:OTEL_TRACES_SAMPLER=""logsunsupported sampler:OTEL_TRACES_SAMPLER_ARG=""withOTEL_TRACES_SAMPLER=traceidratiologs a parse error for the empty stringThis appears to violate the environment variable spec requirement that empty values be interpreted the same way as unset values.
Steps to Reproduce:
mainatb34ee26cf3ea1c56e86f1e546d19c3aea5ded379.Actual Behavior:
Both runs complete, but they log configuration errors even though the env var values are empty:
Expected Behavior:
Empty
OTEL_TRACES_SAMPLERandOTEL_TRACES_SAMPLER_ARGvalues should be treated the same as if those variables were unset.That means:
OTEL_TRACES_SAMPLER=""should behave like the variable is absent: no config error, default sampler behavior.OTEL_TRACES_SAMPLER_ARG=""should behave like the variable is absent: no config error, sampler uses its unset/default argument behavior.Notes:
Spec text at https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/ says:
OTEL_TRACES_SAMPLER_ARGinvalid input must be ignored after logging, but empty input should first hit the empty-value ruleCurrent code path seems to come from
sdk/trace/sampler_env.go:os.LookupEnvis used before trimmingOTEL_TRACES_SAMPLER, so an empty value still enters sampler parsingos.LookupEnvalso makes an emptyOTEL_TRACES_SAMPLER_ARGcount as present, sotraceidratiotries to parse""sdk/trace/provider.gothen passes those returned errors tootel.Handle