Summary
In Effect 4 (4.0.0-beta.102), an ambient OTEL_SERVICE_NAME environment variable overrides an explicitly configured service name for OTLP resource attributes. In Effect 3 the explicit configuration won.
This means telemetry is silently attributed to the ambient name whenever the process environment happens to set one — which is common in CI images, container platforms, managed runtimes, and nix/devenv shells. Nothing errors; spans simply land under the wrong service.
Observed precedence
v3: explicit serviceName > explicit service.name attribute > OTEL_RESOURCE_ATTRIBUTES > OTEL_SERVICE_NAME
v4: reversed — ambient OTEL_SERVICE_NAME wins over explicit configuration
Reproduction
- Set an ambient service name in the environment:
export OTEL_SERVICE_NAME=ambient-name
- Configure an OTLP tracer with an explicit service name (we used
effect/unstable/observability's OtlpTracer layer with an explicitly provided resource service name).
- Emit a single span and inspect the exported resource attributes.
Expected: service.name is the explicitly configured value.
Actual: service.name is ambient-name.
Unsetting only OTEL_SERVICE_NAME, changing nothing else, restores the explicit value.
Evidence from a real suite
Migrating a workspace from Effect 3 to 4.0.0-beta.102, an unchanged telemetry test lane went from 6 failures out of 31 to 1 by unsetting OTEL_SERVICE_NAME alone. The single remaining failure was an unrelated Metric API change.
Five distinct-looking failures had this one root cause. One of them presented as a shutdown flush bug — a post-shutdown span count of 0 — which was actually a false negative: the span was flushed, but under the ambient service name while the assertion queried the configured one. Scope.close and OtlpExporter.Flusher.flush both work correctly.
Why this matters beyond migration
Explicit configuration losing to ambient environment is surprising on its own terms. The failure mode is silent: no error, no warning, just telemetry attributed to the wrong service — and it only becomes visible if something asserts on service.name.
Versions
effect: 4.0.0-beta.102
- Compared against Effect 3 behaviour in the same workspace
Note
Happy to add a standalone minimal reproduction repository if useful — the above steps reproduce it directly, and we can extract a self-contained example on request.
Posted on behalf of @schickling
| field |
value |
agent_name |
cl1-heron |
agent_session_id |
54711470-ae7e-4322-a3e2-129a2689a097 |
agent_tool |
Claude Code |
agent_tool_version |
2.1.220 |
agent_runtime |
Claude Code 2.1.220 |
agent_model |
claude-opus-5 |
runtime_profile |
/nix/store/xg6r3nkr7spjyg2gbl3zprqbsag3fsjc-coding-agent-runtime-profile/share/coding-agents/profile.json |
skills_manifest |
/nix/store/2vkpfkkbc9hjmcwknzkv62v2i44an8mz-agent-skills-corpus/share/agent-skills/manifest.json |
worktree |
effect-utils/schickling/2026-07-28-effect-4 |
machine |
dev3 |
tooling_profile |
dotfiles@unknown-dirty |
Summary
In Effect 4 (
4.0.0-beta.102), an ambientOTEL_SERVICE_NAMEenvironment variable overrides an explicitly configured service name for OTLP resource attributes. In Effect 3 the explicit configuration won.This means telemetry is silently attributed to the ambient name whenever the process environment happens to set one — which is common in CI images, container platforms, managed runtimes, and nix/devenv shells. Nothing errors; spans simply land under the wrong service.
Observed precedence
Reproduction
export OTEL_SERVICE_NAME=ambient-nameeffect/unstable/observability'sOtlpTracerlayer with an explicitly provided resource service name).Expected:
service.nameis the explicitly configured value.Actual:
service.nameisambient-name.Unsetting only
OTEL_SERVICE_NAME, changing nothing else, restores the explicit value.Evidence from a real suite
Migrating a workspace from Effect 3 to
4.0.0-beta.102, an unchanged telemetry test lane went from 6 failures out of 31 to 1 by unsettingOTEL_SERVICE_NAMEalone. The single remaining failure was an unrelatedMetricAPI change.Five distinct-looking failures had this one root cause. One of them presented as a shutdown flush bug — a post-shutdown span count of
0— which was actually a false negative: the span was flushed, but under the ambient service name while the assertion queried the configured one.Scope.closeandOtlpExporter.Flusher.flushboth work correctly.Why this matters beyond migration
Explicit configuration losing to ambient environment is surprising on its own terms. The failure mode is silent: no error, no warning, just telemetry attributed to the wrong service — and it only becomes visible if something asserts on
service.name.Versions
effect:4.0.0-beta.102Note
Happy to add a standalone minimal reproduction repository if useful — the above steps reproduce it directly, and we can extract a self-contained example on request.
Posted on behalf of @schickling
agent_nameagent_session_idagent_toolagent_tool_versionagent_runtimeagent_modelruntime_profileskills_manifestworktreemachinetooling_profile