kataras/iris · error

unsupported response body type: %T

Error message

unsupported response body type: %T

What it means

Client.ReadPlain reads a response body as plain text and only knows how to bind it into *[]byte, *string, or *int. If dest is any other type it returns this error naming the concrete Go type it received. It is a programming/usage error: the wrong destination pointer was passed to ReadPlain.

Source

Thrown at x/client/client.go:456

	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	switch ptr := dest.(type) {
	case *[]byte:
		*ptr = body
		return nil
	case *string:
		*ptr = string(body)
		return nil
	case *int:
		*ptr, err = strconv.Atoi(string(body))
		return err
	default:
		return fmt.Errorf("unsupported response body type: %T", ptr)
	}
}

// GetPlainUnquote reads the response body as raw text and tries to unquote it,
// useful when the remote server sends a single key as a value but due to backend mistake
// it sends it as JSON (quoted) instead of plain text.
func (c *Client) GetPlainUnquote(ctx context.Context, method, urlpath string, payload any, opts ...RequestOption) (string, error) {
	var bodyStr string
	if err := c.ReadPlain(ctx, &bodyStr, method, urlpath, payload, opts...); err != nil {
		return "", err
	}

	s, err := strconv.Unquote(bodyStr)
	if err == nil {
		bodyStr = s
	}

	return bodyStr, nil

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Pass a pointer to string, []byte, or int as dest (e.g. var s string; client.ReadPlain(ctx, &s, ...)).
  2. If you need structured data, use ReadJSON instead of ReadPlain.
  3. For custom types, read into a *string/*[]byte and convert/unmarshal manually afterwards.
  4. Read the %T in the error message to identify the wrongly-typed variable at the call site.

Example fix

// before
var result map[string]any
err := client.ReadPlain(ctx, &result, http.MethodGet, "/api/value", nil)

// after
var s string
err := client.ReadPlain(ctx, &s, http.MethodGet, "/api/value", nil)
// or use ReadJSON for structured types
Defensive patterns

Strategy: type-guard

Validate before calling

func readPlainDestOK(dest any) bool {
    switch dest.(type) {
    case *string, *[]byte, *int:
        return true
    default:
        return false
    }
}
// if !readPlainDestOK(&dest) { use ReadJSON or convert dest }

Type guard

func isReadPlainDest(dest any) bool {
    switch dest.(type) {
    case *string, *[]byte, *int:
        return true
    }
    return false
}

Try / catch

if err := client.ReadPlain(ctx, dest, method, path, nil); err != nil {
    if strings.HasPrefix(err.Error(), "unsupported response body type:") {
        // programmer error: wrong dest type; do not retry, fix call site
        return fmt.Errorf("ReadPlain misuse: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling client.ReadPlain(ctx, dest, method, urlpath, ...) where dest is not *[]byte, *string or *int — e.g. passing a *map[string]any, *struct pointer, or *float64. Also triggered indirectly if GetPlainUnquote's internal *string path is altered; GetPlainUnquote itself is safe since it always passes a *string.

Common situations: Refactoring code from ReadJSON to ReadPlain and forgetting to change the destination to a plain-type pointer; copy-pasting a ReadJSON call with a struct pointer into ReadPlain; passing a typed alias like *MyString (whose underlying type differs at the type-switch level) instead of *string.

Related errors


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/12a0400a702b232f. Report an issue: GitHub.