{"record":{"id":"cdc585405f03f388","repo":"wavetermdev/waveterm","slug":"x-authkey-header-is-invalid","errorCode":null,"errorMessage":"x-authkey header is invalid","messagePattern":"x-authkey header is invalid","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/authkey/authkey.go","lineNumber":23,"sourceCode":"\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n)\n\nvar authkey string\n\nconst WaveAuthKeyEnv = \"WAVETERM_AUTH_KEY\"\nconst AuthKeyHeader = \"X-AuthKey\"\n\nfunc ValidateIncomingRequest(r *http.Request) error {\n\treqAuthKey := r.Header.Get(AuthKeyHeader)\n\tif reqAuthKey == \"\" {\n\t\treturn fmt.Errorf(\"no x-authkey header\")\n\t}\n\tif reqAuthKey != GetAuthKey() {\n\t\treturn fmt.Errorf(\"x-authkey header is invalid\")\n\t}\n\treturn nil\n}\n\nfunc SetAuthKeyFromEnv() error {\n\tauthkey = os.Getenv(WaveAuthKeyEnv)\n\tif authkey == \"\" {\n\t\treturn fmt.Errorf(\"no auth key found in environment variables\")\n\t}\n\tos.Unsetenv(WaveAuthKeyEnv)\n\treturn nil\n}\n\nfunc GetAuthKey() string {\n\treturn authkey\n}\n","sourceCodeStart":5,"sourceCodeEnd":40,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/authkey/authkey.go#L5-L40","documentation":"ValidateIncomingRequest authenticates incoming internal HTTP/WebSocket requests by comparing the x-authkey request header against the in-memory authkey set at startup. If the header value is present but does not match GetAuthKey(), the request is rejected with this error. This protects Wave's internal RPC endpoints from unauthorized local access.","triggerScenarios":"Any HTTP/WS request (HandleWsInternal or anonymous handler) whose x-authkey header holds a stale, wrong, or mismatched value relative to WAVE_AUTHKEY set for the running server process.","commonSituations":"A client (wsh, extension, older frontend) launched with a different WAVE_AUTHKEY value than the server; multiple Wave instances running with different keys; a hardcoded or cached key after the server restarted and picked up a new key.","solutions":["Set the same WAVE_AUTHKEY environment variable for both the server process and the client making the request, then restart both","Verify the server actually accepted the key (SetAuthKeyFromEnv succeeded) and re-read it via GetAuthKey()","Kill duplicate Wave server instances that may be listening with an old key","If the header is set by tooling (proxy, curl script), update the injected header value to match the current key"],"exampleFix":"// before\ncurl -H 'x-authkey: oldkey' http://localhost:2665/awldollar\n// after\nexport WAVE_AUTHKEY=currentkey\ncurl -H \"x-authkey: $WAVE_AUTHKEY\" http://localhost:2665/awldollar","handlingStrategy":"validation","validationCode":"func hasValidAuthKey(r *http.Request, expected string) bool {\n    return r.Header.Get(\"x-authkey\") != \"\" && r.Header.Get(\"x-authkey\") == expected\n}","typeGuard":"func hasAuthHeader(r *http.Request) bool { return r.Header.Get(\"x-authkey\") != \"\" }","tryCatchPattern":"if err := authkey.ValidateIncomingRequest(req); err != nil {\n    if strings.Contains(err.Error(), \"invalid\") { /* key mismatch: refresh key and retry once */ }\n    return err\n}","preventionTips":["Always source WAVE_AUTHKEY from the same environment for server and clients","Restart paired processes together after key changes","Log (hashed) key comparisons when debugging auth failures","Avoid hardcoding auth keys in scripts"],"tags":["auth","http","security"],"backgroundTag":"auth-header-mismatch","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}