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
- Verify Google Chat API credentials and scopes (chat.messages / media upload scope) are valid and unexpired.
- Log the raw response body and HTTP status before decoding to see what the server actually returned.
- Check googleapis.com reachability — a captive portal/proxy may inject non-JSON content.
- 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
- Keep OAuth tokens refreshed and scopes correct for chat media upload.
- Ensure no intercepting proxies inject HTML into googleapis.com responses.
- Log HTTP status and raw body before JSON decoding in custom builds.
- Pin the library to a version matching the current Chat REST API response schema.
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
- googlechat: upload: encode metadata: %w
- googlechat: upload: empty resourceName in response
- decode upload response: %w, body: %s
- googlechat: marshal body: %w
- googlechat: upload: create metadata part: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/1d2cc09207e5875d.
Report an issue: GitHub.