abiosoft/colima · error

failed to decode response

Error message

failed to decode response: %w

What it means

json.NewDecoder(resp.Body).Decode failed while parsing a 200 response from the GitHub releases endpoint into a struct holding only tag_name. Because the status check has already passed, the body received was not the expected JSON — typically an HTML captive-portal/proxy page or a truncated payload. %w chains the underlying *json.SyntaxError or *json.UnmarshalTypeError.

Solutions

  1. Fetch the releases URL manually with curl from the same host and inspect the body actually returned
  2. Configure or bypass HTTP(S) proxies for api.github.com (HTTPS_PROXY, NO_PROXY) so the JSON reaches the client
  3. Retry the command — truncated bodies from transient faults usually decode fine on a second attempt

Example fix

// before
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
	return "", fmt.Errorf("failed to decode response: %w", err)
}

// after
body, err := io.ReadAll(resp.Body)
if err != nil {
	return "", fmt.Errorf("failed to read response: %w", err)
}
if err := json.Unmarshal(body, &release); err != nil {
	snippet := string(body)
	if len(snippet) > 120 {
		snippet = snippet[:120]
	}
	return "", fmt.Errorf("failed to decode response %q: %w", snippet, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the endpoint really returns JSON before depending on the decode
resp, err := http.Get(releasesURL)
if err == nil && resp.Header.Get("Content-Type") != "application/json" {
	// proxy/portal interference: do not attempt the decode
}

Try / catch

var syntaxErr *json.SyntaxError
var typeErr *json.UnmarshalTypeError
switch {
case errors.As(err, &syntaxErr):
	// body was not JSON at all (proxy/portal page): inspect connectivity
case errors.As(err, &typeErr):
	// JSON arrived but the shape changed: parser needs updating
default:
	// unexpected EOF mid-body: retry once
}

Prevention

When it happens

Trigger: A captive portal or HTTPS-inspecting proxy answers 200 with an HTML page; the connection drops mid-body so decoding hits unexpected EOF; a gateway returns 200 with an empty or fragmentary payload.

Common situations: Hotel/airport WiFi captive portals; corporate SSL-MITM appliances; flaky links that truncate responses before the JSON completes.

Understand the failure class

Related errors


AI-assisted analysis of abiosoft/colima@c3a5f9184d (2026-08-15). Data as JSON: /api/errors/f839006560781c7a. Report an issue: GitHub.

Appendix: source

Thrown at model/ramalama.go:57

// getLatestRamalamaVersion fetches the latest release version from GitHub.
func getLatestRamalamaVersion() (string, error) {
	client := &http.Client{Timeout: 10 * time.Second}
	resp, err := client.Get(ramalamaReleasesURL)
	if err != nil {
		return "", fmt.Errorf("failed to fetch releases: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	var release struct {
		TagName string `json:"tag_name"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
		return "", fmt.Errorf("failed to decode response: %w", err)
	}

	// Tag might be "v0.17.1" or "0.17.1"
	version := strings.TrimPrefix(release.TagName, "v")
	return version, nil
}

// ramalamaModel represents a model from ramalama ls --json output.
type ramalamaModel struct {
	Name     string `json:"name"`
	Modified string `json:"modified"`
	Size     int64  `json:"size"`
}

// listRamalamaModels returns all locally available ramalama models.
func listRamalamaModels() ([]ramalamaModel, error) {
	guest := lima.New(host.New())
	output, err := guest.RunOutput("sh", "-c", `export PATH="$HOME/.local/bin:$PATH"; ramalama ls --json 2>/dev/null`)

View on GitHub (pinned to c3a5f9184d)