{"record":{"id":"70e684323c2a3d38","repo":"wavetermdev/waveterm","slug":"client-id-cannot-be-empty","errorCode":null,"errorMessage":"client id cannot be empty","messagePattern":"client id cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsunami/engine/clientimpl.go","lineNumber":129,"sourceCode":"\t\tRootElem:        vdom.H(DefaultComponentName, nil),\n\t}\n\tclient.Root = MakeRoot(client)\n\treturn client\n}\n\nfunc GetDefaultClient() *ClientImpl {\n\treturn defaultClient\n}\n\nfunc (c *ClientImpl) GetIsDone() bool {\n\tc.Lock.Lock()\n\tdefer c.Lock.Unlock()\n\treturn c.IsDone\n}\n\nfunc (c *ClientImpl) checkClientId(clientId string) error {\n\tif clientId == \"\" {\n\t\treturn fmt.Errorf(\"client id cannot be empty\")\n\t}\n\tc.Lock.Lock()\n\tdefer c.Lock.Unlock()\n\tif c.CurrentClientId == \"\" || c.CurrentClientId == clientId {\n\t\tc.CurrentClientId = clientId\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"client id mismatch: expected %s, got %s\", c.CurrentClientId, clientId)\n}\n\nfunc (c *ClientImpl) clientTakeover(clientId string) {\n\tc.Lock.Lock()\n\tdefer c.Lock.Unlock()\n\tc.CurrentClientId = clientId\n}\n\nfunc (c *ClientImpl) doShutdown(reason string) {\n\tc.Lock.Lock()","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/clientimpl.go#L111-L147","documentation":"Validation error from the tsunami client: creating or resolving a client requires a non-empty client ID. An empty ID cannot identify the client to the engine, so the call is rejected immediately.","triggerScenarios":"Calling any ClientImpl method that delegates to checkClientId with clientId == \"\" — e.g. after a failed registration that never produced an id, or constructing the id from an unset config value.","commonSituations":"Config file missing the client id field; empty environment variable interpolated into the id; server returned an empty id on first connect and the client code propagated it.","solutions":["Generate/assign a valid client id before calling client methods (uuid, hostname+pid, etc.)","Validate the id non-empty at config load time","Check where the id originates (server handshake response) and handle empty values there"],"exampleFix":"// before\nclient.Send(cfg.ClientID, msg) // cfg.ClientID == \"\"\n// after\nif cfg.ClientID == \"\" {\n    return errors.New(\"client id must be configured\")\n}\nclient.Send(cfg.ClientID, msg)","handlingStrategy":"validation","validationCode":"if clientID == \"\" {\n    return errors.New(\"client id must be non-empty before calling client\")\n}\nclient.Send(clientID, msg)","typeGuard":"func validClientID(id string) bool { return strings.TrimSpace(id) != \"\" }","tryCatchPattern":"if err := client.Send(id, msg); err != nil {\n    if strings.Contains(err.Error(), \"client id cannot be empty\") {\n        id = generateNewID() // recover by minting a fresh id\n    }\n}","preventionTips":["Validate the id at config load time","Mint ids with uuid.NewString() before first client call","Never propagate a server-returned id without checking non-empty"],"tags":["go","client","validation","identity"],"backgroundTag":"empty-identifier","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}