wavetermdev/waveterm · error
failed to unmarshal response: %w
Error message
failed to unmarshal response: %w
What it means
AuthenticateTokenCommand on a non-root router forwarded the token-verify request to the root and got a response, but utilfn.ReUnmarshal could not decode respData into CommandAuthenticateRtnData. This means the root's response body did not match the expected schema (wrong type, version skew, or error payload in the data slot).
Source
Thrown at pkg/wshutil/wshrouter_controlimpl.go:200
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
}
func (impl *WshRouterControlImpl) AuthenticateJobManagerVerifyCommand(ctx context.Context, data wshrpc.CommandAuthenticateJobManagerData) error {
if !impl.Router.IsRootRouter() {View on GitHub (pinned to a4447c1563)
Solutions
- Log respData raw JSON to see what the root actually returned.
- Check for version skew between the two wshutil binaries and upgrade both to matching versions.
- Verify the root's AuthenticateTokenVerifyCommand returns a properly-typed CommandAuthenticateRtnData, not an error payload.
- Re-run after updating; the error is deterministic if schemas mismatch.
Example fix
// before
err = utilfn.ReUnmarshal(&rtnData, respData)
if err != nil {
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("failed to unmarshal response: %w", err)
}
// after
err = utilfn.ReUnmarshal(&rtnData, respData)
if err != nil {
log.Printf("authenticate-token: bad response payload: %#v", respData)
return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf("failed to unmarshal response: %w", err)
} Defensive patterns
Strategy: try-catch
Type guard
func isValidAuthRtnData(raw json.RawMessage) bool {
var d wshrpc.CommandAuthenticateRtnData
return json.Unmarshal(raw, &d) == nil && d.RouteId != ""
} Try / catch
rtn, err := router.AuthenticateTokenCommand(ctx, data)
if err != nil && strings.Contains(err.Error(), "failed to unmarshal response") {
log.Printf("schema mismatch in token-verify response, upgrade both peers: %v", err)
return errUpgradeRequired
} Prevention
- Keep both ends of the connection on the same wshutil/wave version.
- Log raw response payloads when unmarshal fails to diagnose schema drift.
- Add schema tests for CommandAuthenticateRtnData round-tripping.
When it happens
Trigger: SendRpcRequest(Command_AuthenticateTokenVerify) succeeds but respData cannot be re-marshalled into wshrpc.CommandAuthenticateRtnData — e.g. response is a raw/error object, field types changed, or an older/newer peer returns a different CommandAuthenticateRtnData shape.
Common situations: Version mismatch between client and root router where the RPC response schema changed; the root returning an error object as response data; JSON with a field of the wrong type (e.g. routeid as number instead of string).
Related errors
- invalid input format: %w
- failed to unmarshal input: %w
- cannot convert argument %s.%s type:%T idx:%d error:%v
- error re-marshalling command data: %w
- call ${methodName} error: ${respData.error}
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/00ddd0a3b2e51e28.
Report an issue: GitHub.