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, nil

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped error (%w chain / errors.Unwrap) to find the root cause (timeout vs route-not-found vs invalid token).
  2. Verify the router has an active connection to the root router and that ControlRootRoute is registered.
  3. Regenerate the auth token on the root and retry the authenticate-token handshake.
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/f1114ee009af2b8e. Report an issue: GitHub.