{"record":{"id":"baf409676a51fcaf","repo":"chenhg5/cc-connect","slug":"googlechat-upload-build-request-w","errorCode":null,"errorMessage":"googlechat: upload: build request: %w","messagePattern":"googlechat: upload: build request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/googlechat/googlechat.go","lineNumber":480,"sourceCode":"\tif err := json.NewEncoder(metaPart).Encode(map[string]string{\"filename\": filename}); err != nil {\n\t\treturn \"\", fmt.Errorf(\"googlechat: upload: encode metadata: %w\", err)\n\t}\n\n\tmediaPart, err := mw.CreatePart(textproto.MIMEHeader{\"Content-Type\": {mimeType}})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"googlechat: upload: create media part: %w\", err)\n\t}\n\tif _, err := mediaPart.Write(data); err != nil {\n\t\treturn \"\", fmt.Errorf(\"googlechat: upload: write media: %w\", err)\n\t}\n\tif err := mw.Close(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"googlechat: upload: finalize multipart body: %w\", err)\n\t}\n\n\tuploadURL := chatUploadBase + space + \"/attachments:upload?uploadType=multipart\"\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, buf)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"googlechat: upload: build request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"multipart/related; boundary=\"+mw.Boundary())\n\n\tresp, err := p.doRequest(req)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer func() {\n\t\tif err := resp.Body.Close(); err != nil {\n\t\t\tslog.Warn(\"googlechat: close upload response body\", \"error\", err)\n\t\t}\n\t}()\n\n\tvar result struct {\n\t\tAttachmentDataRef struct {\n\t\t\tResourceName string `json:\"resourceName\"`\n\t\t} `json:\"attachmentDataRef\"`\n\t}","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/googlechat/googlechat.go#L462-L498","documentation":"Returned by uploadAttachment when http.NewRequestWithContext fails to construct the POST request to the Chat media upload endpoint. This only fails if the URL fails http.ParseRequestURI parsing or the method is invalid; since the URL is chatUploadBase + space + a fixed suffix, a malformed space value (containing spaces, control characters, or a bad scheme) is the realistic trigger. It surfaces via postAttachment from SendImage/SendFile.","triggerScenarios":"Calling SendImage()/SendFile() where the resolved space resource name (e.g. spaces/AAA...) is empty or contains characters that break URL parsing — for example an unconfigured or misparsed space ID.","commonSituations":"Config mistakes: missing or wrong space ID in config.toml; a placeholder like \"YOUR_SPACE_ID\" with special characters; accidental whitespace or newlines in the configured space name.","solutions":["Verify the configured Google Chat space ID matches the format spaces/<alphanumeric-id> with no whitespace.","Print/log the composed upload URL (chatUploadBase + space) before the request to inspect the malformed portion.","Trim whitespace/newlines from the space config value at load time.","Obtain the space resource name via the Chat API spaces.list and use the exact resourceName."],"exampleFix":"// before\nspace := cfg.Space // may contain whitespace\n// after\nspace = strings.TrimSpace(cfg.Space)\nif !strings.HasPrefix(space, \"spaces/\") {\n    return fmt.Errorf(\"invalid space %q\", space)\n}","handlingStrategy":"validation","validationCode":"// validate space resource name before sending\nspace = strings.TrimSpace(cfg.Space)\nif !strings.HasPrefix(space, \"spaces/\") || strings.ContainsAny(space, \" \\t\\r\\n\\x00\") {\n    return fmt.Errorf(\"invalid googlechat space %q: want spaces/<id>\", cfg.Space)\n}","typeGuard":"func isValidSpaceName(s string) bool {\n    s = strings.TrimSpace(s)\n    if !strings.HasPrefix(s, \"spaces/\") { return false }\n    id := strings.TrimPrefix(s, \"spaces/\")\n    return id != \"\" && strings.IndexFunc(id, func(r rune) bool {\n        return r < '!' || r > '~'\n    }) == -1\n}","tryCatchPattern":null,"preventionTips":["Trim whitespace from all Google Chat config values at load time.","Verify space IDs against spaces.list API output rather than copying from the UI URL blindly.","Reject placeholder values in config validation at startup.","Keep chatUploadBase and the space name free of concatenated path issues."],"tags":["googlechat","upload","url","config"],"backgroundTag":"invalid-url","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}