wavetermdev/waveterm · error

error validating token: %w

Error message

error validating token: %w

What it means

AuthenticateCommand wraps any failure from ValidateAndExtractRpcContextFromToken (which parses the JWT and extracts the embedded RpcContext) with the message "error validating token: %w". The router received an auth token on a link but could not parse or validate it as a valid JWT carrying a usable RpcContext. The underlying cause is preserved via %w, so check the wrapped message (e.g. signature mismatch, malformed JWT, missing context claim).

Source

Thrown at pkg/wshutil/wshrouter_controlimpl.go:103

		return nil
	}
	return fmt.Errorf("setpeerinfo only valid for proxy connections")
}

func (impl *WshRouterControlImpl) AuthenticateCommand(ctx context.Context, data string) (wshrpc.CommandAuthenticateRtnData, error) {
	handler := GetRpcResponseHandlerFromContext(ctx)
	if handler == nil {
		return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no response handler in context")
	}
	linkId := handler.GetIngressLinkId()
	if linkId == baseds.NoLinkId {
		return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no ingress link found")
	}

	newCtx, err := ValidateAndExtractRpcContextFromToken(data)
	if err != nil {
		log.Printf("wshrouter authenticate error linkid=%d: %v", linkId, err)
		return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("error validating token: %w", err)
	}
	routeId, err := validateRpcContextFromAuth(newCtx)
	if err != nil {
		return wshrpc.CommandAuthenticateRtnData{}, err
	}

	rtnData := wshrpc.CommandAuthenticateRtnData{RouteId: routeId}
	if newCtx.IsRouter {
		log.Printf("wshrouter authenticate success linkid=%d (router)", linkId)
		impl.Router.trustLink(linkId, LinkKind_Router)
	} else {
		log.Printf("wshrouter authenticate success linkid=%d routeid=%q", linkId, routeId)
		impl.Router.trustLink(linkId, LinkKind_Leaf)
		impl.Router.bindRoute(linkId, routeId, true)
	}

	return rtnData, nil
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Unwrap and read the inner error (Go: errors.Unwrap / %v of the result) to see whether the JWT is malformed, has a bad signature, or lacks the RpcContext claim.
  2. Obtain a fresh token from the root router / wave server (e.g. re-run the connection/token-swap flow) instead of reusing a cached one.
  3. Verify client and server are the same Wave Terminal version so the JWT claims (RpcContext shape) match.
  4. Check that the full, untruncated token string is passed as the Authenticate command data (no whitespace/newlines added by shell quoting).

Example fix

// before
err := client.Authenticate(ctx, os.Getenv("OLD_WAVETOKEN"))
// after
token := os.Getenv("WAVETERM_TOKEN")
if token == "" {
    return fmt.Errorf("WAVETERM_TOKEN not set; get a fresh token from the wave server")
}
err := client.Authenticate(ctx, strings.TrimSpace(token))
Defensive patterns

Strategy: validation

Validate before calling

if token == "" || strings.ContainsAny(token, " \n\r\t") {
    return fmt.Errorf("token empty or contains whitespace; re-mint before authenticating")
}
// optionally check JWT has 3 segments
if len(strings.Split(token, ".")) != 3 {
    return fmt.Errorf("token is not a well-formed JWT")
}

Try / catch

// Go
rtn, err := client.Authenticate(ctx, token)
if err != nil {
    var wrappedErr error
    if errors.Unwrap(err) != nil {
        wrappedErr = errors.Unwrap(err)
        log.Printf("token validation root cause: %v", wrappedErr)
    }
    return fmt.Errorf("authenticate failed: %w", err)
}

Prevention

When it happens

Trigger: Calling AuthenticateCommand (via the wsh control RPC) with `data` set to a token string that is not a valid JWT, is signed with a different key than the router expects, has expired, or does not carry a parseable RpcContext claim.

Common situations: wsh clients connecting with a stale token after the server regenerated its keys; copy/paste truncating the JWT; a client built against a different Wave version encoding an incompatible RpcContext; env var WAVETERM_TOKEN pointing at an old token.

Related errors


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