{"record":{"id":"4aeec7e21f917c7b","repo":"fatedier/frp","slug":"invalid-argument-body-can-t-be-empty","errorCode":null,"errorMessage":"invalid argument: body can't be empty","messagePattern":"invalid argument: body can't be empty","errorType":"http","errorClass":"ErrInvalidArgument","httpStatus":400,"severity":"error","filePath":"client/config_manager.go","lineNumber":70,"sourceCode":"\tlog.Infof(\"success reload conf\")\n\treturn nil\n}\n\nfunc (m *serviceConfigManager) ReadConfigFile() (string, error) {\n\tif m.svr.configFilePath == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: frpc has no config file path\", configmgmt.ErrInvalidArgument)\n\t}\n\n\tcontent, err := os.ReadFile(m.svr.configFilePath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: %v\", configmgmt.ErrInvalidArgument, err)\n\t}\n\treturn string(content), nil\n}\n\nfunc (m *serviceConfigManager) WriteConfigFile(content []byte) error {\n\tif len(content) == 0 {\n\t\treturn fmt.Errorf(\"%w: body can't be empty\", configmgmt.ErrInvalidArgument)\n\t}\n\n\tif err := os.WriteFile(m.svr.configFilePath, content, 0o600); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (m *serviceConfigManager) GetProxyStatus() []*proxy.WorkingStatus {\n\treturn m.svr.getAllProxyStatus()\n}\n\nfunc (m *serviceConfigManager) GetProxyConfig(name string) (v1.ProxyConfigurer, bool) {\n\t// Try running proxy manager first\n\tws, ok := m.svr.getProxyStatus(name)\n\tif ok {\n\t\treturn ws.Cfg, true\n\t}","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/config_manager.go#L52-L88","documentation":"Returned by WriteConfigFile (PUT /api/config on the frpc admin API) when the request body is empty. frpc refuses zero-length writes so an empty body cannot truncate and destroy the live config file. It is a pure request-construction error on the caller side.","triggerScenarios":"PUT /api/config with an empty body, a body of only whitespace is fine but zero bytes is not; curl invoked without -d/--data-binary so no body is sent; a CI job whose config template rendered to an empty string.","commonSituations":"Automation that renders a TOML template and PUTs it while the template variables are all empty, yielding a zero-byte payload; curl commands missing --data-binary @file; HTTP clients that drop the body on redirects.","solutions":["Send the complete config file content as the PUT body: curl -X PUT --data-binary @frpc.toml http://127.0.0.1:7400/api/config.","If your tooling produced an empty body, fix the template/render step so it emits at least a minimal valid config.","Verify body length before sending (e.g. test -s frpc.toml) in scripts."],"exampleFix":"# before\ncurl -X PUT http://127.0.0.1:7400/api/config   # 400 body can't be empty\n\n# after\ncurl -X PUT --data-binary @frpc.toml http://127.0.0.1:7400/api/config","handlingStrategy":"validation","validationCode":"// Never send an empty body to PUT /api/config.\nif len(content) == 0 {\n    return errors.New(\"refusing to PUT empty config\")\n}\nreq, _ := http.NewRequest(http.MethodPut, base+\"/api/config\", bytes.NewReader(content))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always PUT with --data-binary @file and test -s the file first","Treat empty rendered templates as a hard error in config pipelines"],"tags":["frp","frpc","config","admin-api","http"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}