{"record":{"id":"992c904a51a55855","repo":"wavetermdev/waveterm","slug":"jobid-mismatch","errorCode":null,"errorMessage":"JobId mismatch","messagePattern":"JobId mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobmanager/mainserverconn.go","lineNumber":83,"sourceCode":"\tlog.Printf(\"authenticateSelfToServer: successfully authenticated to server\\n\")\n\treturn nil\n}\n\nfunc (msc *MainServerConn) AuthenticateToJobManagerCommand(ctx context.Context, data wshrpc.CommandAuthenticateToJobData) error {\n\tjobId, jobAuthToken := WshCmdJobManager.GetJobAuthInfo()\n\n\tclaims, err := wavejwt.ValidateAndExtract(data.JobAccessToken)\n\tif err != nil {\n\t\tlog.Printf(\"AuthenticateToJobManager: failed to validate token: %v\\n\", err)\n\t\treturn fmt.Errorf(\"failed to validate token: %w\", err)\n\t}\n\tif !claims.MainServer {\n\t\tlog.Printf(\"AuthenticateToJobManager: MainServer claim not set\\n\")\n\t\treturn fmt.Errorf(\"MainServer claim not set\")\n\t}\n\tif claims.JobId != jobId {\n\t\tlog.Printf(\"AuthenticateToJobManager: JobId mismatch: expected %s, got %s\\n\", jobId, claims.JobId)\n\t\treturn fmt.Errorf(\"JobId mismatch\")\n\t}\n\tmsc.PeerAuthenticated.Store(true)\n\tlog.Printf(\"AuthenticateToJobManager: authentication successful for JobId=%s\\n\", claims.JobId)\n\n\terr = msc.authenticateSelfToServer(jobAuthToken)\n\tif err != nil {\n\t\tmsc.PeerAuthenticated.Store(false)\n\t\treturn err\n\t}\n\n\tWshCmdJobManager.SetAttachedClient(msc)\n\treturn nil\n}\n\nfunc (msc *MainServerConn) StartJobCommand(ctx context.Context, data wshrpc.CommandStartJobData) (*wshrpc.CommandStartJobRtnData, error) {\n\tlog.Printf(\"StartJobCommand: received command=%s args=%v\", data.Cmd, data.Args)\n\tif !msc.PeerAuthenticated.Load() {\n\t\tlog.Printf(\"StartJobCommand: not authenticated\")","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobmanager/mainserverconn.go#L65-L101","documentation":"The JWT is valid and carries MainServer=true, but the JobId embedded in the token does not match the JobId the job manager is running for. This prevents a token minted for one job from authenticating to another job's manager.","triggerScenarios":"AuthenticateToJobManagerCommand receives a token whose claims.JobId differs from the value returned by WshCmdJobManager.GetJobAuthInfo() — connecting with a token from a different/previous job.","commonSituations":"Reusing tokens across job restarts, mixing up jobIds when managing multiple jobs, stale tokens after a job was recreated with a new id.","solutions":["Regenerate the job access token for the correct jobId and retry authentication.","Confirm the client is connecting to the intended job manager instance (check the jobId in logs: 'expected %s, got %s').","If the job was recreated, refresh auth info via GetJobAuthInfo before authenticating."],"exampleFix":"// before\nauthData.JobAccessToken = oldJobToken // minted for job-123\n// after\njobId, _ := WshCmdJobManager.GetJobAuthInfo()\nauthData.JobAccessToken = issueJobToken(jobId) // token matches current job","handlingStrategy":"validation","validationCode":"jobId, _ := WshCmdJobManager.GetJobAuthInfo()\n// verify token jobId matches before authenticating\ntokClaims, err := wavejwt.ValidateAndExtract(token)\nif err == nil && tokClaims.JobId != jobId {\n    return fmt.Errorf(\"token is for job %s, manager is %s\", tokClaims.JobId, jobId)\n}","typeGuard":null,"tryCatchPattern":"if err := conn.AuthenticateToJobManagerCommand(ctx, authData); err != nil {\n    if strings.Contains(err.Error(), \"JobId mismatch\") {\n        authData.JobAccessToken = issueTokenForJob(currentJobId)\n        err = conn.AuthenticateToJobManagerCommand(ctx, authData)\n    }\n    if err != nil { return err }\n}","preventionTips":["Track one token per jobId; never reuse across jobs","Re-mint tokens after a job is recreated","Log expected vs actual jobId on auth failure"],"tags":["jwt","authentication","jobmanager","security"],"backgroundTag":"jwt-claim-mismatch","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}