{"record":{"id":"3392cf41d4289308","repo":"chenhg5/cc-connect","slug":"googlechat-missing-space-in-reply-context","errorCode":null,"errorMessage":"googlechat: missing space in reply context","messagePattern":"googlechat: missing space in reply context","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/googlechat/googlechat.go","lineNumber":419,"sourceCode":"// The caller is responsible for draining and closing resp.Body on success.\nfunc (p *Platform) doRequest(req *http.Request) (*http.Response, error) {\n\tresp, err := p.botClient.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.StatusCode >= 300 {\n\t\treturn nil, httpErrorBody(resp, fmt.Sprintf(\"googlechat: %s %s\", req.Method, req.URL.Path))\n\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}","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/googlechat/googlechat.go#L401-L437","documentation":"After confirming the reply context type, post validates that a target space is present, since every Chat API send URL is built from the space resource name. An empty space field means the replyContext is structurally valid but carries no destination, so sending is impossible and the error is returned before any HTTP request is made.","triggerScenarios":"A replyContext constructed with an empty space — e.g. ReconstructReplyCtx given a key like \"googlechat:\" or \"googlechat:t/foo\" where nothing precedes the thread separator, or user-scoped key parsing yielding an empty space.","commonSituations":"Corrupted or truncated session keys stored by cron/send-to-session features; a session created before any space was known; hand-edited persisted session keys.","solutions":["Verify the persisted session key contains a non-empty space after the \"googlechat:\" prefix (e.g. googlechat:spaces/AAAA)","Delete/recreate the affected session so a fresh key is captured from a real inbound message","Add a check on session-key save time to reject keys without a space resource name"],"exampleFix":"// before\nkey := \"googlechat:t/xyz\"           // empty space\n\n// after\nkey := \"googlechat:spaces/AAAA:t/xyz\"","handlingStrategy":"validation","validationCode":"func (rc replyContext) valid() bool { return strings.HasPrefix(rc.space, \"spaces/\") }","typeGuard":null,"tryCatchPattern":"if err := p.Send(ctx, rc, msg); err != nil {\n    if strings.Contains(err.Error(), \"missing space\") {\n        slog.Warn(\"googlechat session has no space; dropping send\", \"key\", sessionKey)\n        return nil // or recreate the session\n    }\n}","preventionTips":["Reject session keys without a spaces/ segment when persisting them","Recreate sessions whose space was deleted rather than sending into a stale key","Log the session key at capture time so corrupted keys are caught early"],"tags":["googlechat","validation","session"],"backgroundTag":"empty-required-field","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"}