{"record":{"id":"8189ef9d9766768f","repo":"wavetermdev/waveterm","slug":"mainserver-claim-not-set","errorCode":null,"errorMessage":"MainServer claim not set","messagePattern":"MainServer claim not set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobmanager/mainserverconn.go","lineNumber":79,"sourceCode":"\t\tlog.Printf(\"authenticateSelfToServer: failed to authenticate to server: %v\\n\", err)\n\t\treturn fmt.Errorf(\"failed to authenticate to server: %w\", err)\n\t}\n\tmsc.SelfAuthenticated.Store(true)\n\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","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobmanager/mainserverconn.go#L61-L97","documentation":"The token itself is valid, but its claims lack MainServer=true, meaning the JWT was not issued by/for the main server in the job-manager trust model. The job manager requires this claim to accept peer authentication, rejecting tokens issued for other purposes.","triggerScenarios":"AuthenticateToJobManagerCommand receives a valid JWT whose parsed claims have MainServer == false (token minted without the MainServer claim, or a different token type passed in).","commonSituations":"Passing a user/access token instead of a job access token, an older server version issuing tokens without the claim, or custom token issuance code omitting MainServer.","solutions":["Use a token issued by the main server that includes MainServer: true in its claims.","Update both server and client to matching versions so token issuance includes the claim.","Check the token-issuing code path to ensure wavejwt claims set MainServer."],"exampleFix":"// before\ntoken := wavejwt.MakeToken(secret, claims) // claims missing MainServer\n// after\nclaims.MainServer = true\ntoken := wavejwt.MakeToken(secret, claims)","handlingStrategy":"validation","validationCode":"claims, err := wavejwt.ValidateAndExtract(token)\nif err == nil && !claims.MainServer {\n    return fmt.Errorf(\"token lacks MainServer claim; use a main-server-issued job token\")\n}","typeGuard":null,"tryCatchPattern":"if err := conn.AuthenticateToJobManagerCommand(ctx, authData); err != nil {\n    if strings.Contains(err.Error(), \"MainServer claim not set\") {\n        return fmt.Errorf(\"wrong token type: request a job access token from the main server\")\n    }\n    return err\n}","preventionTips":["Use only tokens minted by the main server's job issuance path","Keep server versions in sync so claim sets match","Decode token claims locally to sanity-check before sending"],"tags":["jwt","authentication","claims","security"],"backgroundTag":"jwt-missing-claim","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}