router-for-me/CLIProxyAPI · warning

failed to read body

Error message

failed to read body

What it means

requestedAuthFileNamesForDelete accepts deletion targets via query params (`?name=...`) or, failing that, by reading the request body. If io.ReadAll on the body errors it returns `failed to read body` — the connection failed while reading the (optional) JSON body carrying name/names for the delete request. Note the underlying read error is deliberately dropped from the message.

Source

Thrown at internal/api/handlers/management/auth_files_crud.go:292

	}
	if err := h.upsertAuthRecord(ctx, auth); err != nil {
		return err
	}
	return nil
}

func requestedAuthFileNamesForDelete(c *gin.Context) ([]string, error) {
	if c == nil {
		return nil, nil
	}
	names := uniqueAuthFileNames(c.QueryArray("name"))
	if len(names) > 0 {
		return names, nil
	}

	body, err := io.ReadAll(c.Request.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read body")
	}
	body = bytes.TrimSpace(body)
	if len(body) == 0 {
		return nil, nil
	}

	var objectBody struct {
		Name  string   `json:"name"`
		Names []string `json:"names"`
	}
	if body[0] == '[' {
		var arrayBody []string
		if err := json.Unmarshal(body, &arrayBody); err != nil {
			return nil, fmt.Errorf("invalid request body")
		}
		return uniqueAuthFileNames(arrayBody), nil
	}
	if err := json.Unmarshal(body, &objectBody); err != nil {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Retry the delete request — body read failures are almost always connection-level and transient.
  2. Prefer the query-parameter form (?name=auth.json) which needs no body at all.
  3. Ensure the client sends Content-Length correctly or uses no body for DELETE.
  4. Check for proxy/LB request timeouts between client and management API.

Example fix

# before: body-based delete that can fail mid-read
$ curl -X DELETE http://127.0.0.1:8000/v0/management/auth-files -d '{"name":"a.json"}'

# after: query-param delete, no body
$ curl -X DELETE 'http://127.0.0.1:8000/v0/management/auth-files?name=a.json'
Defensive patterns

Strategy: retry

Type guard

func isBodyReadFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "failed to read body")
}

Try / catch

if isBodyReadFailure(err) {
    // prefer query-param delete which needs no body
    err = deleteViaQueryParams(names)
}

Prevention

When it happens

Trigger: DELETE request whose body transfer aborts mid-read (client disconnect, connection reset, proxy timeout); malformed chunked encoding; client sending a body with a bad Content-Length.

Common situations: REST clients that stream a body then abort; intermediary proxies resetting long-lived connections; automation retrying a DELETE while the previous socket is half-closed.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/396fe2bfea24f40d. Report an issue: GitHub.