wavetermdev/waveterm · error

no rpccontext in token response

Error message

no rpccontext in token response

What it means

The token verification succeeded structurally, but the returned CommandAuthenticateRtnData has a nil RpcContext. The router requires RpcContext to know the identity of the authenticated peer before trusting the link and binding its route; without it the handshake result is unusable.

Source

Thrown at pkg/wshutil/wshrouter_controlimpl.go:205

		}
	} 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
}

func (impl *WshRouterControlImpl) AuthenticateJobManagerVerifyCommand(ctx context.Context, data wshrpc.CommandAuthenticateJobManagerData) error {
	if !impl.Router.IsRootRouter() {
		return fmt.Errorf("authenticatejobmanagerverify can only be called on root router")
	}

	if data.JobId == "" {
		return fmt.Errorf("no jobid in authenticatejobmanager message")

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check the root router code path that builds CommandAuthenticateRtnData and ensure it sets RpcContext.
  2. Regenerate the token with the current version of the wave client so embedded context is present.
  3. Verify the token content passed to extractTokenData / verify includes the rpc context fields.
  4. Confirm no version skew strips RpcContext during ReUnmarshal.

Example fix

// before
if rtnData.RpcContext == nil {
    return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no rpccontext in token response")
}
// after (caller-side check before trusting result)
if rtnData.RpcContext == nil {
    return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("no rpccontext in token response: regenerate token with current client version")
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate token embeds an rpc context before handshake
if token == "" || !strings.Contains(token, ".") {
    return fmt.Errorf("malformed token: expected signed token with embedded context")
}

Type guard

func hasRpcContext(d wshrpc.CommandAuthenticateRtnData) bool {
    return d.RpcContext != nil
}

Try / catch

rtn, err := router.AuthenticateTokenCommand(ctx, data)
if err != nil && strings.Contains(err.Error(), "no rpccontext in token response") {
    return fmt.Errorf("regenerate token with current client version: %w", err)
}

Prevention

When it happens

Trigger: The root router's AuthenticateTokenVerifyCommand produced/returned a CommandAuthenticateRtnData with RpcContext unset — typically when the token payload was valid enough to verify but the root failed to populate the RpcContext (corrupt token data, or a root implementation that omits it).

Common situations: Custom or modified root implementations that return partial data; a token generated by an incompatible tool that lacks embedded rpc context; schema drift where RpcContext moved/renamed.

Related errors


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