{"record":{"id":"43422bcb67ca907a","repo":"fatedier/frp","slug":"get-natholerespmsg-error-invalid-message-type","errorCode":null,"errorMessage":"get natHoleRespMsg error: invalid message type","messagePattern":"get natHoleRespMsg error: invalid message type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nathole/nathole.go","lineNumber":107,"sourceCode":"\tctx context.Context, transporter transport.MessageTransporter,\n\tproxyName string, timeout time.Duration,\n) error {\n\ttimeoutCtx, cancel := context.WithTimeout(ctx, timeout)\n\tdefer cancel()\n\n\tvar natHoleRespMsg *msg.NatHoleResp\n\ttransactionID := NewTransactionID()\n\tm, err := transporter.Do(timeoutCtx, &msg.NatHoleVisitor{\n\t\tTransactionID: transactionID,\n\t\tProxyName:     proxyName,\n\t\tPreCheck:      true,\n\t}, transactionID, msg.TypeNameNatHoleResp)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get natHoleRespMsg error: %v\", err)\n\t}\n\tmm, ok := m.(*msg.NatHoleResp)\n\tif !ok {\n\t\treturn fmt.Errorf(\"get natHoleRespMsg error: invalid message type\")\n\t}\n\tnatHoleRespMsg = mm\n\n\tif natHoleRespMsg.Error != \"\" {\n\t\treturn fmt.Errorf(\"%s\", natHoleRespMsg.Error)\n\t}\n\treturn nil\n}\n\n// Prepare is used to do some preparation work before penetration.\nfunc Prepare(stunServers []string, opts PrepareOptions) (*PrepareResult, error) {\n\t// discover for Nat type\n\taddrs, localAddr, err := Discover(stunServers, \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"discover error: %v\", err)\n\t}\n\tif len(addrs) < 2 {\n\t\treturn nil, fmt.Errorf(\"discover error: not enough addresses\")","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/nathole/nathole.go#L89-L125","documentation":"Returned by nathole.PreCheck (pkg/nathole/nathole.go) when transporter.Do returns a message that is not *msg.NatHoleResp even though the request registered msg.TypeNameNatHoleResp as the expected response. The transport is supposed to correlate replies by transaction and expected type; a different concrete type indicates a protocol or transport-layer inconsistency rather than a user config problem.","triggerScenarios":"nathole.PreCheck where the message dispatcher delivers an unexpected type for the transaction — e.g. a custom MessageTransporter implementation with lax type matching, a version-skewed peer sending a different response shape, or a deserialization path that decodes into the wrong struct.","commonSituations":"Custom transporters that do not honor the expected-response-type argument; frpc/frps version mismatch changing response encoding; tests with mock transporters returning generic messages.","solutions":["Use the stock transport implementation provided by frp rather than a custom MessageTransporter","Align frpc and frps versions","In mock/test transporters, make Do return exactly *msg.NatHoleResp for NatHoleVisitor requests","Log the concrete type returned by Do to see what actually arrived"],"exampleFix":"// before (mock transporter returning wrong type)\nfunc (m *mockTP) Do(...) (msg.Message, error) { return &msg.Pong{}, nil }\n\n// after\nfunc (m *mockTP) Do(...) (msg.Message, error) { return &msg.NatHoleResp{}, nil }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isNatHoleResp(m msg.Message) bool {\n    _, ok := m.(*msg.NatHoleResp)\n    return ok\n}","tryCatchPattern":"m, err := tp.Do(ctx, req, tid, msg.TypeNameNatHoleResp)\nif err != nil {\n    return err\n}\nif !isNatHoleResp(m) {\n    // transport delivered an unexpected type: treat as protocol violation, reset transport\n}","preventionTips":["Use frp's stock MessageTransporter; honor expected-type in custom ones","Mock transporters must return *msg.NatHoleResp for NatHoleVisitor","Keep peer versions aligned"],"tags":["go","frp","nathole","protocol","testing"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}