{"record":{"id":"11a7af10aa74a370","repo":"dagger/dagger","slug":"missing-session-id","errorCode":null,"errorMessage":"missing session ID","messagePattern":"missing session ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/server/session.go","lineNumber":1097,"sourceCode":"\n\treturn client.getClientCaller(ctx, id)\n}\n\nfunc (srv *Server) clientFromContext(ctx context.Context) (*daggerClient, error) {\n\tclientMetadata, err := engine.ClientMetadataFromContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get client metadata for session call: %w\", err)\n\t}\n\tclient, err := srv.clientFromIDs(clientMetadata.SessionID, clientMetadata.ClientID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn client, nil\n}\n\nfunc (srv *Server) clientFromIDs(sessID, clientID string) (*daggerClient, error) {\n\tif sessID == \"\" {\n\t\treturn nil, fmt.Errorf(\"missing session ID\")\n\t}\n\tif clientID == \"\" {\n\t\treturn nil, fmt.Errorf(\"missing client ID\")\n\t}\n\tsrv.daggerSessionsMu.RLock()\n\tsess, ok := srv.daggerSessions[sessID]\n\tsrv.daggerSessionsMu.RUnlock()\n\tif !ok {\n\t\t// This error can happen due to per-LLB-vertex deduplication in the buildkit solver,\n\t\t// where for instance the first client cancels and closes its session while others\n\t\t// are waiting on the result. In this case its safe to retry the operation again with\n\t\t// the still connected client metadata.\n\t\terr := flightcontrol.RetryableError{Err: fmt.Errorf(\"session %q not found\", sessID)}\n\t\treturn nil, err\n\t}\n\n\t// Gate on the session's lifecycle state via a lock-free atomic read (never\n\t// lifecycleMu), so this lookup can't block on a session that is initializing","sourceCodeStart":1079,"sourceCodeEnd":1115,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/engine/server/session.go#L1079-L1115","documentation":"clientFromIDs validates that a non-empty session ID was supplied before looking up the session in srv.daggerSessions. An empty session ID means the call cannot be routed to any session, so this sentinel error is returned.","triggerScenarios":"A call path resolves client metadata whose SessionID field is the empty string, then calls srv.clientFromIDs(\"\", clientID).","commonSituations":"Malformed or absent client metadata on the wire, custom tooling invoking engine internals without a session, or bugs where a default/zero-value ClientMetadata struct is passed through.","solutions":["Ensure the caller sets engine.ClientMetadata with a valid SessionID before making calls","Check where the metadata was produced for why SessionID is empty","Re-create the session via the SDK so a real session ID is issued","Verify SDK/engine version compatibility for metadata encoding"],"exampleFix":"// before\nclient, err := srv.clientFromIDs(md.SessionID, md.ClientID) // md.SessionID == \"\"\n// after\ncustom := engine.ClientMetadata{SessionID: sessID, ClientID: md.ClientID}\nclient, err := srv.clientFromIDs(custom.SessionID, custom.ClientID)","handlingStrategy":"validation","validationCode":"// Go\nif md.SessionID == \"\" {\n    return errors.New(\"cannot call engine: session ID is empty\")\n}","typeGuard":null,"tryCatchPattern":"// Go\nif err != nil && err.Error() == \"missing session ID\" {\n    // re-create the session and retry the call\n}","preventionTips":["Never construct zero-value ClientMetadata structs","Obtain session IDs from Connect/session setup","Validate metadata before internal calls"],"tags":["engine","session","validation","missing-id"],"backgroundTag":"missing-session-id","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"}