{"record":{"id":"888ff57af4b38b2c","repo":"dagger/dagger","slug":"starting-client-terminal-session-w","errorCode":null,"errorMessage":"starting client terminal session: %w","messagePattern":"starting client terminal session: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/session/terminal/terminal.go","lineNumber":200,"sourceCode":"}\n\nfunc NewTerminalProxy(client TerminalClient) TerminalProxy {\n\treturn TerminalProxy{\n\t\tclient: client,\n\t}\n}\n\nfunc (p TerminalProxy) Register(srv *grpc.Server) {\n\tRegisterTerminalServer(srv, p)\n}\n\nfunc (p TerminalProxy) Session(stream Terminal_SessionServer) error {\n\tctx, cancel := context.WithCancelCause(stream.Context())\n\tdefer cancel(errors.New(\"proxy stream closed\"))\n\n\tclientStream, err := p.client.Session(grpcutil.IncomingToOutgoingContext(ctx))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"starting client terminal session: %w\", err)\n\t}\n\treturn grpcutil.ProxyStream[anypb.Any](ctx, clientStream, stream)\n}\n","sourceCodeStart":182,"sourceCodeEnd":204,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/engine/session/terminal/terminal.go#L182-L204","documentation":"Returned by TerminalProxy.Session when opening the outbound gRPC client stream to the upstream terminal service fails. The proxy accepts an incoming Session stream, then dials a client Session on the target engine; if that Dial/Session call errors (connection refused, unavailable, auth), the proxy returns this wrapped error.","triggerScenarios":"A TerminalProxy is registered (e.g. engine-to-engine or session-to-CLI proxying) and p.client.Session(ctx) fails at stream creation — target engine unreachable, gRPC server not yet serving, context already cancelled, or TLS/auth rejection.","commonSituations":"dagger terminal against a remote/cloud engine where the engine connection dropped; nested terminal proxying (dagger-in-dagger) where the inner engine hasn't started; network partitions or VPN drops during session attach.","solutions":["Check connectivity to the target engine (dagger core dump / engine status) and retry","Ensure the engine session is fully started before attaching a terminal","Inspect proxy stream context cancellation — a cancelled incoming stream aborts the client dial","Verify TLS/metadata (grpcutil.IncomingToOutgoingContext) forwards required auth headers"],"exampleFix":"// before\nclientStream, err := p.client.Session(grpcutil.IncomingToOutgoingContext(ctx))\nif err != nil { return fmt.Errorf(\"starting client terminal session: %w\", err) }\n// after\nclientStream, err := p.client.Session(grpcutil.IncomingToOutgoingContext(ctx))\nif err != nil {\n\tif status.Code(err) == codes.Unavailable { /* retry with backoff */ }\n\treturn fmt.Errorf(\"starting client terminal session: %w\", err)\n}","handlingStrategy":"retry","validationCode":"# shell: confirm the engine is reachable before opening a terminal session\ndagger query --help >/dev/null 2>&1 || { echo 'engine unreachable'; exit 1; }","typeGuard":null,"tryCatchPattern":"err := openTerminalSession(ctx)\nif err != nil {\n\tif status.Code(errors.Unwrap(err)) == codes.Unavailable {\n\t\t// backoff and reconnect to the engine, then retry\n\t\treturn retryWithBackoff(openTerminalSession, ctx)\n\t}\n\treturn err\n}","preventionTips":["Verify engine connectivity before interactive attach","Wait for engine/session startup completion before proxying terminals","Forward auth/TLS metadata via grpcutil.IncomingToOutgoingContext"],"tags":["grpc","terminal","proxy","connection"],"backgroundTag":"grpc-unavailable","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}