{"record":{"id":"39d1164634b60f0e","repo":"chenhg5/cc-connect","slug":"googlechat-attachment-message-build-request-w","errorCode":null,"errorMessage":"googlechat: attachment message: build request: %w","messagePattern":"googlechat: attachment message: build request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/googlechat/googlechat.go","lineNumber":542,"sourceCode":"}\n\n// postAttachment uploads data then creates a Chat message carrying the\n// attachmentDataRef. Shared by SendImage and SendFile.\nfunc (p *Platform) postAttachment(ctx context.Context, rc replyContext, filename, mimeType string, data []byte) error {\n\tif rc.space == \"\" {\n\t\treturn fmt.Errorf(\"googlechat: missing space in reply context\")\n\t}\n\tresourceName, err := p.uploadAttachment(ctx, rc.space, filename, mimeType, data)\n\tif err != nil {\n\t\treturn err\n\t}\n\turl, body, err := buildAttachmentRequest(rc, resourceName)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"googlechat: attachment message: build request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := p.doRequest(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err := io.Copy(io.Discard, resp.Body); err != nil {\n\t\t_ = resp.Body.Close()\n\t\treturn fmt.Errorf(\"googlechat: drain attachment create response body: %w\", err)\n\t}\n\tif err := resp.Body.Close(); err != nil {\n\t\treturn fmt.Errorf(\"googlechat: close attachment create response body: %w\", err)\n\t}\n\treturn nil\n}\n\n// SendImage uploads an image and posts it as a Chat message attachment.\n// Implements core.ImageSender.","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/googlechat/googlechat.go#L524-L560","documentation":"This wraps an http.NewRequestWithContext failure while building the JSON POST that creates a Chat message referencing an uploaded attachment. NewRequest only errors on invalid URL or unsupported methods, so this almost always means the URL produced by buildAttachmentRequest is malformed.","triggerScenarios":"buildAttachmentRequest returns a URL that fails net/http URL parsing — e.g. missing/empty base API URL in configuration producing a non-absolute URL, or mis-escaped characters in the space/resource name interpolated into the path.","commonSituations":"Deployments overriding the Chat API base URL with a bad value; space names containing characters that break URL construction; regression in buildAttachmentRequest after a version upgrade.","solutions":["Print/log the URL produced by buildAttachmentRequest and validate it parses with url.Parse","Verify the API base URL configuration points at https://chat.googleapis.com/...","Ensure the attachmentDataRef resource name is URL-escaped before being placed in the request path"],"exampleFix":"// before\nurl := apiBase + rc.space + \"/attachments\" // raw space name\n// after\nurl := apiBase + url.PathEscape(rc.space) + \"/attachments\"","handlingStrategy":"try-catch","validationCode":"if _, err := url.Parse(requestURL); err != nil || !strings.HasPrefix(requestURL, \"https://\") { return fmt.Errorf(\"invalid attachment URL: %w\", err) }","typeGuard":null,"tryCatchPattern":"if err := p.SendFile(ctx, rc, file); err != nil {\n    if strings.Contains(err.Error(), \"build request\") {\n        slog.Error(\"googlechat attachment URL invalid\", \"error\", err)\n    }\n    return err\n}","preventionTips":["Validate custom API base URLs at startup","URL-escape all resource names","Pin and test the API URL builder"],"tags":["googlechat","http","url"],"backgroundTag":"invalid-url","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}