{"record":{"id":"bbd4118e4a906623","repo":"fatedier/frp","slug":"unmarshal-http-response-error-s","errorCode":null,"errorMessage":"unmarshal http response error: %s","messagePattern":"unmarshal http response error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sdk/client/client.go","lineNumber":46,"sourceCode":"}\n\nfunc (c *Client) SetAuth(user, pwd string) {\n\tc.authUser = user\n\tc.authPwd = pwd\n}\n\nfunc (c *Client) GetProxyStatus(ctx context.Context, name string) (*model.ProxyStatusResp, error) {\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"http://\"+c.address+\"/api/status\", nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcontent, err := c.do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tallStatus := make(model.StatusResp)\n\tif err = json.Unmarshal([]byte(content), &allStatus); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal http response error: %s\", strings.TrimSpace(content))\n\t}\n\tfor _, pss := range allStatus {\n\t\tfor _, ps := range pss {\n\t\t\tif ps.Name == name {\n\t\t\t\treturn &ps, nil\n\t\t\t}\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"no proxy status found\")\n}\n\nfunc (c *Client) GetAllProxyStatus(ctx context.Context) (model.StatusResp, error) {\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", \"http://\"+c.address+\"/api/status\", nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcontent, err := c.do(req)\n\tif err != nil {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/sdk/client/client.go#L28-L64","documentation":"Returned by Client.GetProxyStatus when the frpc admin API's /api/status response body is not valid JSON for model.StatusResp. The raw body is included in the message instead of the unmarshal error, which usually reveals an HTML error page or auth failure text coming back instead of JSON.","triggerScenarios":"Calling GetProxyStatus against an address that is not the frpc admin server (e.g. the proxy port, or a reverse proxy returning 200 with an HTML page); the admin API returning a success status but a non-JSON body; a body truncated mid-transfer.","commonSituations":"Wrong webServer.port/address in frpc config; a proxy or load balancer in front of frpc rewriting responses; an auth token that yields a 200-wrapped error page from some middleware.","solutions":["Point the client at frpc's admin address (webServer.addr:webServer.port from frpc.toml), not at the frps server or a proxy port.","Curl http://<admin-addr>/api/status manually and inspect the body shown in the error to identify what is actually answering.","Remove any reverse-proxy layer that rewrites or wraps the admin API responses."],"exampleFix":"// before\nclient := client.New(\"127.0.0.1:7000\") // frps bind port, wrong\n\n// after\n// use frpc webServer port, e.g. webServer.port = 7400 in frpc.toml\nclient := client.New(\"127.0.0.1:7400\")","handlingStrategy":"validation","validationCode":"// verify the admin API answers JSON before relying on it\nresp, err := http.Get(\"http://\" + c.address + \"/api/status\")\nif err != nil { return err }\nif ct := resp.Header.Get(\"Content-Type\"); !strings.Contains(ct, \"application/json\") {\n    return fmt.Errorf(\"%s is not the frpc admin API (content-type %s)\", c.address, ct)\n}","typeGuard":null,"tryCatchPattern":"if _, err := client.GetProxyStatus(ctx, name); err != nil {\n    if strings.Contains(err.Error(), \"unmarshal http response\") {\n        // wrong endpoint answering: check webServer.port in frpc.toml, do not retry\n    }\n}","preventionTips":["Construct the SDK client from the same webServer.host/port values as frpc.toml.","Smoke-test GET /api/status with curl when setting up the admin server."],"tags":["sdk","http","json","frpc-admin","go"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}