wavetermdev/waveterm · error
failed to verify token: %w
Error message
failed to verify token: %w
What it means
This error is returned by AuthenticateTokenCommand when the router is NOT the root router and the forwarded AuthenticateTokenVerify RPC to the root router (via ControlRootRoute) fails. It wraps the underlying transport/RPC error, so the root cause is chained via %w. It indicates the token could not be verified upstream, not that the token itself is necessarily bad.
Source
Thrown at pkg/wshutil/wshrouter_controlimpl.go:196
var rtnData wshrpc.CommandAuthenticateRtnData
var err error
if impl.Router.IsRootRouter() {
rtnData, err = extractTokenData(data.Token)
if err != nil {
log.Printf("wshrouter authenticate-token error linkid=%d: %v", linkId, err)
return wshrpc.CommandAuthenticateRtnData{}, err
}
} else {
wshRpc := GetWshRpcFromContext(ctx)
if wshRpc == nil {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no wshrpc in context")
}
respData, err := wshRpc.SendRpcRequest(wshrpc.Command_AuthenticateTokenVerify, data, &wshrpc.RpcOpts{Route: ControlRootRoute})
if err != nil {
log.Printf("wshrouter authenticate-token error linkid=%d: failed to verify token: %v", linkId, err)
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("failed to verify token: %w", err)
}
err = utilfn.ReUnmarshal(&rtnData, respData)
if err != nil {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("failed to unmarshal response: %w", err)
}
}
if rtnData.RpcContext == nil {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no rpccontext in token response")
}
if rtnData.RouteId == "" {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no routeid in token response")
}
log.Printf("wshrouter authenticate-token success linkid=%d routeid=%q", linkId, rtnData.RouteId)
impl.Router.trustLink(linkId, LinkKind_Leaf)
impl.Router.bindRoute(linkId, rtnData.RouteId, true)
return rtnData, nilView on GitHub (pinned to a4447c1563)
Solutions
- Inspect the wrapped error (%w chain / errors.Unwrap) to find the root cause (timeout vs route-not-found vs invalid token).
- Verify the router has an active connection to the root router and that ControlRootRoute is registered.
- Regenerate the auth token on the root and retry the authenticate-token handshake.
- Check wshrouter logs for the matching 'authenticate-token error linkid=...' line to see the raw underlying error.
Example fix
// before
respData, err := wshRpc.SendRpcRequest(wshrpc.Command_AuthenticateTokenVerify, data, &wshrpc.RpcOpts{Route: ControlRootRoute})
if err != nil {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("failed to verify token: %w", err)
}
// after
respData, err := wshRpc.SendRpcRequest(wshrpc.Command_AuthenticateTokenVerify, data, &wshrpc.RpcOpts{Route: ControlRootRoute, Timeout: 10 * time.Second})
if err != nil {
if errors.Is(err, wshutil.ErrRouteNotFound) {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("root router unreachable: %w", err)
}
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("failed to verify token: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// caller-side: only attempt when a route to the root is likely registered
if !router.HasRoute(wshutil.ControlRootRoute) {
return fmt.Errorf("root router not connected; cannot verify token yet")
} Type guard
func errIsTransport(err error) bool {
var netErr net.Error
return errors.As(err, &netErr)
} Try / catch
rtn, err := router.AuthenticateTokenCommand(ctx, data)
if err != nil {
var wrapped *wshutil.RpcErr
if errors.As(err, &wrapped) || errors.Is(err, context.DeadlineExceeded) {
// transient: retry with backoff
return retryWithBackoff(func() error { _, err := router.AuthenticateTokenCommand(ctx, data); return err })
}
return fmt.Errorf("token verify failed permanently: %w", err)
} Prevention
- Always keep an active root-router connection before starting the token handshake.
- Set explicit RPC timeouts so verification failures surface quickly and can be retried.
- Regenerate tokens regularly and match client/server wshutil versions.
- Read the wrapped cause with errors.Unwrap before deciding on retry vs abort.
When it happens
Trigger: Calling authenticate-token on a non-root router whose SendRpcRequest(Command_AuthenticateTokenVerify) to the control root route fails — e.g. no route to root, root not connected, RPC timeout, or the remote AuthenticateTokenVerifyCommand returning an error (invalid/expired token).
Common situations: Relay/middle-layer router forwarding a leaf's connection handshake while the upstream link to the root is down; token expired or revoked on the root; typo in route to ControlRootRoute; network drop mid-handshake.
Related errors
- failed to verify job auth token: %w
- failed to list workspaces: %v
- failed to list blocks from all %d workspace(s)
- error getting jwt public key: %v
- error authenticating with upstream: %v
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/f1114ee009af2b8e.
Report an issue: GitHub.