wavetermdev/waveterm · error
client id mismatch: expected %s, got %s
Error message
client id mismatch: expected %s, got %s
What it means
checkClientId enforces single-client semantics: once CurrentClientId is set, calls with a different id are rejected with this mismatch error. This detects a second client (or a restarted client with a new id) trying to act on the same ClientImpl.
Source
Thrown at tsunami/engine/clientimpl.go:137
}
func (c *ClientImpl) GetIsDone() bool {
c.Lock.Lock()
defer c.Lock.Unlock()
return c.IsDone
}
func (c *ClientImpl) checkClientId(clientId string) error {
if clientId == "" {
return fmt.Errorf("client id cannot be empty")
}
c.Lock.Lock()
defer c.Lock.Unlock()
if c.CurrentClientId == "" || c.CurrentClientId == clientId {
c.CurrentClientId = clientId
return nil
}
return fmt.Errorf("client id mismatch: expected %s, got %s", c.CurrentClientId, clientId)
}
func (c *ClientImpl) clientTakeover(clientId string) {
c.Lock.Lock()
defer c.Lock.Unlock()
c.CurrentClientId = clientId
}
func (c *ClientImpl) doShutdown(reason string) {
c.Lock.Lock()
defer c.Lock.Unlock()
if c.IsDone {
return
}
c.DoneReason = reason
c.IsDone = true
close(c.DoneCh)
}View on GitHub (pinned to a4447c1563)
Solutions
- Reuse the same clientId consistently for the lifetime of the ClientImpl (store it once at first successful call)
- Call clientTakeover deliberately when a new client should replace the old one
- On mismatch, log both ids and reinitialize or restart the client cleanly
Example fix
// before
client.Do(newRandomUUID(), req) // new id every call
// after
if myClientID == "" { myClientID = newRandomUUID() }
client.Do(myClientID, req) Defensive patterns
Strategy: validation
Validate before calling
var myClientID string
func ensureClientID(c *tsunami.ClientImpl, id string) (string, error) {
if myClientID == "" { myClientID = id }
if id != myClientID {
return "", fmt.Errorf("must use client id %s, got %s", myClientID, id)
}
return myClientID, nil
} Try / catch
if err := client.Send(id, msg); err != nil {
if strings.Contains(err.Error(), "client id mismatch") {
log.Printf("stale id %q; reinitializing client session", id)
client = reinitClient()
}
} Prevention
- Generate the id once and reuse it for the client's lifetime
- Persist the id across reconnects instead of regenerating
- Use clientTakeover explicitly when a replacement is intended
When it happens
Trigger: Calling a client method with clientId X while CurrentClientId is Y (already claimed by a previous call). The claim is set on first successful checkClientId and only changed via clientTakeover.
Common situations: Reconnecting after a crash with a newly generated id while the old ClientImpl is still in use; two goroutines/processes sharing one client with different ids; stale cached id from a previous session.
Related errors
- client id cannot be empty
- cannot connect to %q when status is %q
- no webcontents found with blockid ${data.blockid}
- beginning of file
- procinfo: process not found
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/c61b0bb9c3ae9076.
Report an issue: GitHub.