{"record":{"id":"5315bc695f50380b","repo":"dagger/dagger","slug":"session-id-is-required","errorCode":null,"errorMessage":"session ID is required","messagePattern":"session ID is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/server/session.go","lineNumber":1162,"sourceCode":"\treturn client, nil\n}\n\n// initialize session+client if needed, return:\n// * the initialized client\n// * a cleanup func to run when the call is done\n//\n//nolint:gocyclo // session/client initialization is an intentionally linear state machine.\nfunc (srv *Server) getOrInitClient(\n\tctx context.Context,\n\topts *ClientInitOpts,\n) (_ *daggerClient, _ func() error, rerr error) {\n\tif srv.isShuttingDown() {\n\t\treturn nil, nil, errServerShuttingDown\n\t}\n\n\tsessionID := opts.SessionID\n\tif sessionID == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"session ID is required\")\n\t}\n\tclientID := opts.ClientID\n\tif clientID == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"client ID is required\")\n\t}\n\ttoken := opts.ClientSecretToken\n\tif token == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"client secret token is required\")\n\t}\n\n\t// cleanup to do if this method fails; the failure handler that runs these is\n\t// installed below, once we hold the session's lifecycleMu (so it can publish\n\t// the removed tombstone before unlocking, then drop it only after cleanups).\n\tfailureCleanups := &cleanups.Cleanups{}\n\n\t// get or initialize the session as a whole\n\n\tsrv.daggerSessionsMu.Lock()","sourceCodeStart":1144,"sourceCodeEnd":1180,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/engine/server/session.go#L1144-L1180","documentation":"Returned by Server.getOrInitClient when ClientInitOpts.SessionID is empty. Every engine session is keyed by session ID; the transport or caller omitted it, which is a protocol violation caught before any client state is created.","triggerScenarios":"ClientInitOpts constructed programmatically (e.g. by an SDK or nested-client path) without setting SessionID.","commonSituations":"Custom tooling or module code building client init options by hand; SDK bug leaving metadata unset; constructing options from a zero-valued struct.","solutions":["Populate opts.SessionID with the session's ID before calling connect/init","Obtain the ID from the parent client's metadata rather than leaving it empty","Fix the SDK/tool path that builds ClientInitOpts to always propagate the session ID"],"exampleFix":"// before\nopts := &ClientInitOpts{ClientID: cid, ClientSecretToken: tok}\n// after\nopts := &ClientInitOpts{SessionID: sessID, ClientID: cid, ClientSecretToken: tok}","handlingStrategy":"validation","validationCode":"if opts.SessionID == \"\" { return errors.New(\"SessionID must be set before connecting\") }","typeGuard":"func optsValid(o *ClientInitOpts) bool { return o != nil && o.SessionID != \"\" && o.ClientID != \"\" && o.ClientSecretToken != \"\" }","tryCatchPattern":"if err := connect(opts); err != nil {\n    if strings.Contains(err.Error(), \"session ID is required\") { return fmt.Errorf(\"caller bug: SessionID not set: %w\", err) }\n    return err\n}","preventionTips":["Validate ClientInitOpts fields before passing them to connect APIs","Source SessionID from the parent client's metadata","Add a unit test asserting opts are fully populated"],"tags":["validation","session","go","config"],"backgroundTag":"missing-required-argument","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"}