{"record":{"id":"44f6183faa121a09","repo":"dagger/dagger","slug":"workspace-client-metadata-w","errorCode":null,"errorMessage":"workspace client metadata: %w","messagePattern":"workspace client metadata: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/workspace_context.go","lineNumber":160,"sourceCode":"// client-scoped resolvers — CurrentServedDeps, EnsureWorkspaceModules — resolve\n// against the workspace's own served modules rather than whichever client is\n// currently executing. Synthetic/value workspaces have no owning client, so ctx\n// is returned unchanged and resolution falls back to the current client.\n//\n// This mirrors core/schema's withWorkspaceClientContext, reimplemented here so\n// the LLM's schema derivation ([WorkspaceServedSchema]) needs no core→schema\n// import.\nfunc workspaceClientContext(ctx context.Context, ws *Workspace) (context.Context, error) {\n\tif ws.ClientID == \"\" {\n\t\treturn ctx, nil\n\t}\n\tquery, err := CurrentQuery(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tclientMetadata, err := query.SpecificClientMetadata(ctx, ws.ClientID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"workspace client metadata: %w\", err)\n\t}\n\treturn engine.ContextWithClientMetadata(ctx, clientMetadata), nil\n}\n\n// WorkspaceServedSchema returns the stable served GraphQL schema for a\n// Workspace. Pending overlays are resolved only by explicit agent\n// recomposition; bound object tools retain the schema that defined them.\nfunc WorkspaceServedSchema(ctx context.Context, ws dagql.ObjectResult[*Workspace]) (*dagql.Server, error) {\n\twsCtx, err := WorkspaceServedContext(ctx, ws)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tquery, err := CurrentQuery(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdeps, err := query.CurrentServedDeps(wsCtx)\n\tif err != nil {","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/workspace_context.go#L142-L178","documentation":"This error wraps a failure from query.SpecificClientMetadata when workspaceClientContext tries to switch the context to the Workspace's owning client. Only workspaces with a non-empty ClientID take this path; synthetic/value workspaces return early. If the owning client's metadata cannot be looked up (client no longer registered in the engine's client registry, e.g. the owning session disconnected), the lookup fails and this wrapped error is returned to WorkspaceServedContext / WorkspaceServedSchema.","triggerScenarios":"Calling WorkspaceServedContext or WorkspaceServedSchema with a Workspace whose ClientID is set but whose owning client session is gone: the client that created the workspace disconnected/closed, the ClientID is stale (workspace persisted or passed across sessions), or the metadata store lookup errors.","commonSituations":"An LLM/agent tool (bound via withWorkspace) referencing a Workspace whose originating client call has already returned; replaying a workspace across a new dagger session; engine restart invalidating old client IDs; holding a Workspace object result longer than its owning call's lifetime.","solutions":["Re-obtain the Workspace in the current session (re-select currentWorkspace or rebuild it) instead of reusing a Workspace from a previous/foreign client.","Ensure the owning client session stays alive for as long as the Workspace is used (don't let the parent call return before dependent tool/schema calls).","If the workspace is synthetic/value-only, verify ClientID is empty so the client switch is skipped.","Check the wrapped error for 'client not found' style messages to confirm the owning session ended; then rebind the workspace to the current client."],"exampleFix":"// before: reusing a workspace captured from an earlier session\nws := savedWorkspaceFromPreviousSession\nschema, err := core.WorkspaceServedSchema(ctx, ws)\n// after: reload the workspace in the live session\nvar ws dagql.ObjectResult[*core.Workspace]\nsrv.Select(ctx, srv.Root(), &ws, dagql.Selector{Field: \"currentWorkspace\"})\nschema, err := core.WorkspaceServedSchema(ctx, ws)","handlingStrategy":"validation","validationCode":"// only reuse a workspace whose owning client is still the live one\nif ws.Self().ClientID != \"\" && ws.Self().ClientID != currentSessionClientID {\n    // reload the workspace in the current session before calling WorkspaceServedSchema\n    return errors.New(\"workspace belongs to a finished client session; reload it\")\n}","typeGuard":"func workspaceOwnedByLiveClient(ws *core.Workspace, liveClientID string) bool {\n    return ws.ClientID == \"\" || ws.ClientID == liveClientID\n}","tryCatchPattern":"ctx, err := core.WorkspaceServedContext(ctx, ws)\nif err != nil {\n    if strings.Contains(err.Error(), \"workspace client metadata\") {\n        // owning client gone: reload workspace in current session and retry once\n    }\n    return err\n}","preventionTips":["Don't retain Workspace object results beyond their owning call/session lifetime.","Reload workspaces from the live session instead of caching them across sessions.","Keep the owning client session open while dependent schema/inspect calls run.","Treat empty ClientID (synthetic workspaces) as safe to reuse anywhere."],"tags":["go","dagger","client-metadata","session-lifecycle"],"backgroundTag":"client-session-not-found","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"}