{"record":{"id":"aa3de9b83b499218","repo":"github/copilot-sdk","slug":"set-environment-variables-via-either-the-client-le-aa3de9","errorCode":null,"errorMessage":"Set environment variables via either the client-level Env option or the connection's Env, not both. Prefer the connection-level Env for child-process transports.","messagePattern":"Set environment variables via either the client-level Env option or the connection's Env, not both\\. Prefer the connection-level Env for child-process transports\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/client.go","lineNumber":124,"sourceCode":"// transports each own their OS process, so per-connection env is allowed, but\n// setting it in both the client-level option and the connection is rejected.\nfunc validateEnvironmentOptions(connection RuntimeConnection, opts *ClientOptions) {\n\tif _, ok := connection.(InProcessConnection); ok {\n\t\tif opts.Env != nil {\n\t\t\tpanic(\"Env is not supported with InProcessConnection: the in-process transport loads the native runtime into the shared host process, whose single environment block cannot carry per-client values. Set the variables on the host process environment instead.\")\n\t\t}\n\t\tif opts.WorkingDirectory != \"\" {\n\t\t\tpanic(\"WorkingDirectory is not supported with InProcessConnection: the native runtime shares the host process working directory. Use a child-process transport, or set the process working directory before creating the client.\")\n\t\t}\n\t\tif opts.Telemetry != nil {\n\t\t\tpanic(\"Telemetry is not supported with InProcessConnection: telemetry configuration is lowered to environment variables read by native runtime code running in the shared host process, so per-client telemetry cannot be honored in-process. Configure telemetry via the host process environment, or use a child-process transport.\")\n\t\t}\n\t\treturn\n\t}\n\n\tif cp, ok := connection.(childProcessConnection); ok {\n\t\tif cp.connEnv() != nil && opts.Env != nil {\n\t\t\tpanic(\"Set environment variables via either the client-level Env option or the connection's Env, not both. Prefer the connection-level Env for child-process transports.\")\n\t\t}\n\t}\n}\n\n// Client manages the connection to the Copilot CLI server and provides session management.\n//\n// The Client can either spawn a CLI server process or connect to an existing server.\n// It handles JSON-RPC communication, session lifecycle, tool execution, and permission requests.\n//\n// Example:\n//\n//\t// Create a client with default options (spawns CLI server using stdio)\n//\tclient := copilot.NewClient(nil)\n//\n//\t// Or connect to an existing server\n//\tclient := copilot.NewClient(&copilot.ClientOptions{\n//\t    Connection: copilot.URIConnection{URL: \"localhost:3000\"},\n//\t})","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/client.go#L106-L142","documentation":"NewClient panics when environment variables are supplied twice for a child-process transport: both the client-level ClientOptions.Env and the connection's own Env (e.g. StdioConnection.Env) are non-nil. The library rejects the ambiguity so it is always clear which environment block the child receives; the connection-level Env is the preferred location.","triggerScenarios":"Calling NewClient with a childProcessConnection (e.g. StdioConnection{Env: ...}) whose connEnv() is non-nil while ClientOptions.Env is also non-nil. Panics in validateEnvironmentOptions (go/client.go:124).","commonSituations":"Refactoring that moves Env from client options onto the connection (or vice versa) leaves the old setting in place; copying example code that sets Env in both places.","solutions":["Remove ClientOptions.Env and keep the Env on the connection (preferred for child-process transports).","Alternatively remove the connection-level Env and keep only ClientOptions.Env.","Note: an explicit empty connection env (non-nil, empty map) is authoritative, so nil-ing the client-level Env is enough."],"exampleFix":"// before\nclient := clientpkg.NewClient(&clientpkg.Options{\n    Env: map[string]string{\"FOO\": \"bar\"},\n    Connection: clientpkg.StdioConnection{\n        Env: map[string]string{\"FOO\": \"bar\"},\n    },\n})\n// after\nclient := clientpkg.NewClient(&clientpkg.Options{\n    Connection: clientpkg.StdioConnection{\n        Env: map[string]string{\"FOO\": \"bar\"},\n    },\n})","handlingStrategy":"validation","validationCode":"if opts.Env != nil {\n    if cp, ok := opts.Connection.(clientpkg.StdioConnection); ok && cp.Env != nil {\n        return fmt.Errorf(\"Env set on both client options and connection\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt one convention: always put child-process env on the connection, never on client options.","Search codebase for 'Env:' assignments to the client options when refactoring.","Centralize client construction in a single helper so env placement is consistent."],"tags":["go","panic","environment","configuration","duplicate-options"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}