{"record":{"id":"dcbdb3611eea1b7f","repo":"docker/compose","slug":"restoring-env-for-q-w","errorCode":null,"errorMessage":"restoring env for %q: %w","messagePattern":"restoring env for %q: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/tracing/docker_context.go","lineNumber":55,"sourceCode":"func traceClientFromDockerContext(dockerCli command.Cli, otelEnv envMap) (otlptrace.Client, error) {\n\t// attempt to extract an OTEL config from the Docker context to enable\n\t// automatic integration with Docker Desktop;\n\tcfg, err := ConfigFromDockerContext(dockerCli.ContextStore(), dockerCli.CurrentContext())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"loading otel config from docker context metadata: %w\", err)\n\t}\n\n\tif cfg.Endpoint == \"\" {\n\t\treturn nil, nil\n\t}\n\n\t// HACK: unfortunately _all_ public OTEL initialization functions\n\t// \timplicitly read from the OS env, so temporarily unset them all and\n\t// \trestore afterwards\n\tdefer func() {\n\t\tfor k, v := range otelEnv {\n\t\t\tif err := os.Setenv(k, v); err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"restoring env for %q: %w\", k, err))\n\t\t\t}\n\t\t}\n\t}()\n\tfor k := range otelEnv {\n\t\tif err := os.Unsetenv(k); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"stashing env for %q: %w\", k, err)\n\t\t}\n\t}\n\n\tconn, err := grpc.NewClient(cfg.Endpoint,\n\t\tgrpc.WithContextDialer(memnet.DialEndpoint),\n\t\t// this dial is restricted to using a local Unix socket / named pipe,\n\t\t// so there is no need for TLS\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"initializing otel connection from docker context metadata: %w\", err)\n\t}","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/internal/tracing/docker_context.go#L37-L73","documentation":"To keep public OTEL init functions from reading OS env vars, traceClientFromDockerContext temporarily unsets all OTEL_* variables and restores them afterwards in a defer. If os.Setenv fails while restoring a key, the function panics with 'restoring env for %q: %w'. This is a hard crash, not a returned error, and it can leave the env half-restored.","triggerScenarios":"os.Setenv(k, v) failing during the deferred restore loop: process out of memory allocating the new env string, or (on Windows) a concurrent env mutation race; reachable only after an OTEL endpoint was configured via Docker context and the client init path executed.","commonSituations":"Extreme memory pressure at tracing init; rare platform-level env failures; tests that mutate the environment from parallel goroutines while compose initializes tracing.","solutions":["Check the wrapped %w (typically OOM-related) and address memory pressure / raise limits for the compose process","Eliminate concurrent env mutation: do not run code that sets OTEL_* vars in parallel with startup","If seen in tests, serialize env-touching tests or unset OTEL_* before invoking compose APIs","Upgrade compose — a panic here is a last-resort guard, and newer builds may harden this path"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null // a panic in library code cannot be pre-validated","typeGuard":null,"tryCatchPattern":"// wrap InitTracing in a recover at the top-level CLI boundary; log and continue without tracing rather than crashing the run\n defer func() { if r := recover(); r != nil { log.Warnf(\"tracing init crashed: %v\", r) } }()","preventionTips":["Avoid mutating OTEL_* env vars concurrently with startup","Ensure adequate memory at process start","Pin recent compose versions that harden this path"],"tags":["otel","environment","panic","tracing","go"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}