{"record":{"id":"60a2f4bd09224e43","repo":"wavetermdev/waveterm","slug":"sock-claim-is-missing-or-invalid","errorCode":null,"errorMessage":"sock claim is missing or invalid","messagePattern":"sock claim is missing or invalid","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshutil.go","lineNumber":384,"sourceCode":"\tif !ok {\n\t\treturn nil, fmt.Errorf(\"error getting claims from token\")\n\t}\n\treturn claimsToRpcCtx(claims), nil\n}\n\n// only for use on client\nfunc ExtractUnverifiedSocketName(tokenStr string) (string, error) {\n\ttoken, _, err := new(jwt.Parser).ParseUnverified(tokenStr, &wavejwt.WaveJwtClaims{})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error parsing token: %w\", err)\n\t}\n\tclaims, ok := token.Claims.(*wavejwt.WaveJwtClaims)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"error getting claims from token\")\n\t}\n\tsockName := claims.Sock\n\tif sockName == \"\" {\n\t\treturn \"\", fmt.Errorf(\"sock claim is missing or invalid\")\n\t}\n\tsockName = wavebase.ExpandHomeDirSafe(sockName)\n\treturn sockName, nil\n}\n\nfunc getShell() string {\n\tif runtime.GOOS == \"darwin\" {\n\t\treturn shellutil.GetMacUserShell()\n\t}\n\tshell := os.Getenv(\"SHELL\")\n\tif shell == \"\" {\n\t\treturn \"/bin/bash\"\n\t}\n\treturn strings.TrimSpace(shell)\n}\n\nfunc GetInfo() wshrpc.RemoteInfo {\n\treturn wshrpc.RemoteInfo{","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshutil.go#L366-L402","documentation":"The token parsed and claims were of the correct type, but the 'sock' claim is empty, so there is no socket path to return. Wave requires every wsh connection token to carry the domain socket path it was issued for.","triggerScenarios":"Calling ExtractUnverifiedSocketName with a Wave JWT that lacks a non-empty sock claim — e.g. a token minted by custom code, an old token format, or a claims struct where sock was never set.","commonSituations":"Hand-built or third-party-minted tokens; server upgrade changing token contents while a cached old token is reused; copying a token from a different tool.","solutions":["Regenerate the connection token from the actual Wave server ('wsh server') so the sock claim is populated","Verify with a JWT decoder (e.g. jwt.io) that the payload contains a non-empty 'sock' field","Ensure client and server are the same Wave version"],"exampleFix":"// before\nsock, err := wshutil.ExtractUnverifiedSocketName(oldToken)\n// after\n// regenerate the token from the running server, then:\nout, _ := exec.Command(\"wsh\", \"server\", \"--token-only\").Output()\nsock, err := wshutil.ExtractUnverifiedSocketName(strings.TrimSpace(string(out)))","handlingStrategy":"validation","validationCode":"func tokenHasSock(tokenStr string) bool {\n    parts := strings.Split(strings.TrimSpace(tokenStr), \".\")\n    if len(parts) != 3 { return false }\n    payload, err := base64.RawURLEncoding.DecodeString(parts[1])\n    if err != nil { return false }\n    var c struct{ Sock string `json:\"sock\"` }\n    return json.Unmarshal(payload, &c) == nil && c.Sock != \"\"\n}","typeGuard":null,"tryCatchPattern":"sockName, err := wshutil.ExtractUnverifiedSocketName(tokenStr)\nif err != nil {\n    return fmt.Errorf(\"token lacks sock claim; reissue via 'wsh server': %w\", err)\n}","preventionTips":["Never hand-craft or edit Wave tokens; use 'wsh server' output","Verify token payload contains a non-empty 'sock' before relying on it","Refresh cached tokens after any server upgrade"],"tags":["jwt","claims","socket","wsh"],"backgroundTag":"jwt-missing-claim","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}