{"record":{"id":"00ddd0a3b2e51e28","repo":"wavetermdev/waveterm","slug":"failed-to-unmarshal-response-w","errorCode":null,"errorMessage":"failed to unmarshal response: %w","messagePattern":"failed to unmarshal response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrouter_controlimpl.go","lineNumber":200,"sourceCode":"\tif impl.Router.IsRootRouter() {\n\t\trtnData, err = extractTokenData(data.Token)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"wshrouter authenticate-token error linkid=%d: %v\", linkId, err)\n\t\t\treturn wshrpc.CommandAuthenticateRtnData{}, err\n\t\t}\n\t} else {\n\t\twshRpc := GetWshRpcFromContext(ctx)\n\t\tif wshRpc == nil {\n\t\t\treturn wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"no wshrpc in context\")\n\t\t}\n\t\trespData, err := wshRpc.SendRpcRequest(wshrpc.Command_AuthenticateTokenVerify, data, &wshrpc.RpcOpts{Route: ControlRootRoute})\n\t\tif err != nil {\n\t\t\tlog.Printf(\"wshrouter authenticate-token error linkid=%d: failed to verify token: %v\", linkId, err)\n\t\t\treturn wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"failed to verify token: %w\", err)\n\t\t}\n\t\terr = utilfn.ReUnmarshal(&rtnData, respData)\n\t\tif err != nil {\n\t\t\treturn wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n\t\t}\n\t}\n\n\tif rtnData.RpcContext == nil {\n\t\treturn wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"no rpccontext in token response\")\n\t}\n\tif rtnData.RouteId == \"\" {\n\t\treturn wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"no routeid in token response\")\n\t}\n\tlog.Printf(\"wshrouter authenticate-token success linkid=%d routeid=%q\", linkId, rtnData.RouteId)\n\timpl.Router.trustLink(linkId, LinkKind_Leaf)\n\timpl.Router.bindRoute(linkId, rtnData.RouteId, true)\n\n\treturn rtnData, nil\n}\n\nfunc (impl *WshRouterControlImpl) AuthenticateJobManagerVerifyCommand(ctx context.Context, data wshrpc.CommandAuthenticateJobManagerData) error {\n\tif !impl.Router.IsRootRouter() {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrouter_controlimpl.go#L182-L218","documentation":"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).","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nerr = utilfn.ReUnmarshal(&rtnData, respData)\nif err != nil {\n    return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n}\n// after\nerr = utilfn.ReUnmarshal(&rtnData, respData)\nif err != nil {\n    log.Printf(\"authenticate-token: bad response payload: %#v\", respData)\n    return wshrpc.CommandAuthenticateRtnData{}, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isValidAuthRtnData(raw json.RawMessage) bool {\n    var d wshrpc.CommandAuthenticateRtnData\n    return json.Unmarshal(raw, &d) == nil && d.RouteId != \"\"\n}","tryCatchPattern":"rtn, err := router.AuthenticateTokenCommand(ctx, data)\nif err != nil && strings.Contains(err.Error(), \"failed to unmarshal response\") {\n    log.Printf(\"schema mismatch in token-verify response, upgrade both peers: %v\", err)\n    return errUpgradeRequired\n}","preventionTips":["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."],"tags":["rpc","json","unmarshal"],"backgroundTag":"response-unmarshal-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}