chenhg5/cc-connect · error

googlechat: upload: decode response: %w

Error message

googlechat: upload: decode response: %w

What it means

Returned by uploadAttachment when the JSON response from the Chat media upload endpoint cannot be decoded into the expected {attachmentDataRef:{resourceName}} structure. Typically the server returned an error payload (HTML error page, OAuth error JSON, or empty body) rather than the expected shape. It surfaces via postAttachment from SendImage/SendFile.

Source

Thrown at platform/googlechat/googlechat.go:501

	resp, err := p.doRequest(req)
	if err != nil {
		return "", err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			slog.Warn("googlechat: close upload response body", "error", err)
		}
	}()

	var result struct {
		AttachmentDataRef struct {
			ResourceName string `json:"resourceName"`
		} `json:"attachmentDataRef"`
	}
	defer func() { _, _ = io.Copy(io.Discard, resp.Body) }()
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return "", fmt.Errorf("googlechat: upload: decode response: %w", err)
	}
	if result.AttachmentDataRef.ResourceName == "" {
		return "", fmt.Errorf("googlechat: upload: empty resourceName in response")
	}
	return result.AttachmentDataRef.ResourceName, nil
}

// buildAttachmentRequest builds the Chat REST API URL and JSON body to post a
// message that references an already-uploaded attachment (by resource name).
// Threading behaviour mirrors buildSendRequest.
func buildAttachmentRequest(rc replyContext, resourceName string) (string, []byte, error) {
	body := map[string]any{
		"attachment": []map[string]any{
			{"attachmentDataRef": map[string]any{"resourceName": resourceName}},
		},
	}
	applyThread(body, rc)
	b, err := json.Marshal(body)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Verify Google Chat API credentials and scopes (chat.messages / media upload scope) are valid and unexpired.
  2. Log the raw response body and HTTP status before decoding to see what the server actually returned.
  3. Check googleapis.com reachability — a captive portal/proxy may inject non-JSON content.
  4. Pin/verify the Chat REST API version used by the library; response schema changes break decoding.

Example fix

// before
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
    return "", fmt.Errorf("googlechat: upload: decode response: %w", err)
}
// after
raw, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
    return "", fmt.Errorf("googlechat: upload: status %d: %s", resp.StatusCode, raw)
}
if err := json.Unmarshal(raw, &result); err != nil {
    return "", fmt.Errorf("googlechat: upload: decode response: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: verify credentials/scopes before uploading
if !checkOAuthToken(ctx) { // refresh token if expired
    return fmt.Errorf("google chat credentials invalid or expired")
}

Type guard

func hasAttachmentDataRef(raw []byte) bool {
    var probe struct {
        AttachmentDataRef struct {
            ResourceName string `json:"resourceName"`
        } `json:"attachmentDataRef"`
    }
    return json.Unmarshal(raw, &probe) == nil
}

Try / catch

name, err := p.SendFile(ctx, target, path)
if err != nil {
    if strings.Contains(err.Error(), "decode response") && isTransient(err) {
        // retry once after refreshing credentials
        time.Sleep(time.Second)
        return p.SendFile(ctx, target, path)
    }
    return err
}

Prevention

When it happens

Trigger: Calling SendImage()/SendFile(); the upload POST returns a response whose body is not valid JSON or does not match the result struct — e.g. an auth error body, truncated response, or proxy-injected content.

Common situations: Expired/missing OAuth credentials returning an error JSON with unexpected fields; a proxy returning an HTML error page; API version changes altering the response schema; non-2xx responses not being checked before decode.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/1d2cc09207e5875d. Report an issue: GitHub.