{"record":{"id":"ce3d2c27be32829e","repo":"chenhg5/cc-connect","slug":"googlechat-build-request-w","errorCode":null,"errorMessage":"googlechat: build request: %w","messagePattern":"googlechat: build request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/googlechat/googlechat.go","lineNumber":427,"sourceCode":"\t}\n\treturn resp, nil\n}\n\nfunc (p *Platform) post(ctx context.Context, rctx any, content string) error {\n\trc, ok := rctx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"googlechat: invalid reply context type %T\", rctx)\n\t}\n\tif rc.space == \"\" {\n\t\treturn fmt.Errorf(\"googlechat: missing space in reply context\")\n\t}\n\turl, body, err := buildSendRequest(rc, content)\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: 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 response body: %w\", err)\n\t}\n\tif err := resp.Body.Close(); err != nil {\n\t\treturn fmt.Errorf(\"googlechat: close response body: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (p *Platform) Reply(ctx context.Context, rctx any, content string) error {\n\treturn p.post(ctx, rctx, content)","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/googlechat/googlechat.go#L409-L445","documentation":"post wraps http.NewRequestWithContext failures with this error. Since the URL is built from the validated reply context and the body is plain JSON bytes, this almost always means the URL failed http.NewRequest's parsing (control characters or invalid characters in the space/thread resource names) or the context was already canceled.","triggerScenarios":"replyContext containing a space or thread value with invalid URL characters (newlines, spaces, control bytes) that make the composed URL unparseable, or a canceled/expired context passed to Reply/Send.","commonSituations":"Malicious or corrupted inbound event data used to build the space/thread fields; session keys containing whitespace; long-running operations whose context was canceled before the send.","solutions":["Inspect the wrapped inner error: if it's url.Parse-related, sanitize the space/thread values (reject control/whitespace characters when building replyContext)","If it's a context-canceled error, check upstream cancellation — recreate the context or skip sends on shutdown","Recreate the session if its stored space/thread fields were corrupted by bad input"],"exampleFix":"// before\nthread := strings.TrimSpace(rawThread) // may still contain control chars\n// after\nif !validResourceName(thread) { return fmt.Errorf(\"googlechat: bad thread %q\", thread) }","handlingStrategy":"validation","validationCode":"func validResourceName(s string) bool {\n    for _, r := range s { if r < 0x21 || r == 0x7f { return false } }\n    return strings.HasPrefix(s, \"spaces/\")\n}","typeGuard":null,"tryCatchPattern":"if err := p.post(ctx, rc, content); err != nil {\n    if errors.Is(err, context.Canceled) {\n        slog.Info(\"send aborted: context canceled (shutdown?)\")\n        return err\n    }\n    return fmt.Errorf(\"send failed: %w\", err)\n}","preventionTips":["Sanitize space/thread values parsed from inbound events before storing them in replyContext","Don't reuse contexts across long-lived operations; create one per send","Validate session keys on save so invalid characters never reach URL construction"],"tags":["googlechat","http","url"],"backgroundTag":"http-request-failed","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"}