{"record":{"id":"80a1fa6bd2d27d08","repo":"chenhg5/cc-connect","slug":"not-connected","errorCode":null,"errorMessage":"not connected","messagePattern":"not connected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/matrix/matrix.go","lineNumber":677,"sourceCode":"func (p *Platform) isDirectedAtBot(content *event.MessageEventContent, selfID id.UserID) bool {\n\t// Check formatted body for matrix.to link\n\tif content.FormattedBody != \"\" {\n\t\tmention := fmt.Sprintf(\"https://matrix.to/#/%s\", selfID)\n\t\tif strings.Contains(content.FormattedBody, mention) {\n\t\t\treturn true\n\t\t}\n\t}\n\t// Check plain body for @user:server mention\n\tif strings.Contains(content.Body, selfID.String()) {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (p *Platform) downloadMediaContent(ctx context.Context, contentURL id.ContentURIString) ([]byte, error) {\n\tclient := p.getClient()\n\tif client == nil {\n\t\treturn nil, fmt.Errorf(\"not connected\")\n\t}\n\tparsed, err := contentURL.Parse()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse content URI: %w\", err)\n\t}\n\tresp, err := client.Download(ctx, parsed)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\treturn io.ReadAll(resp.Body)\n}\n\nfunc (p *Platform) downloadMedia(ctx context.Context, content *event.MessageEventContent) (*core.ImageAttachment, error) {\n\tdata, err := p.downloadMediaContent(ctx, content.URL)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/matrix/matrix.go#L659-L695","documentation":"downloadMediaContent returns \"not connected\" when the platform's Matrix client is nil, meaning the platform has not finished connecting or the connection was cleared. Media downloads (images, files, audio) require an authenticated client to fetch content from the Matrix homeserver, so they refuse to run without one. This is a state guard, not a network failure.","triggerScenarios":"Calling downloadMedia / downloadFileMedia / downloadAudioMedia (via downloadMediaContent) when p.getClient() returns nil — i.e., before Start() completes the client setup or after clearClient() nulled p.client during shutdown/reconnect.","commonSituations":"A media message arrives while the platform is reconnecting after a lost sync connection; messages queued during startup race with client initialization; Stop() was called (p.stopping) and clearClient() ran but in-flight event handling still tries to download an attachment.","solutions":["Wait for the platform to finish connecting (ensure Start() succeeded) before sending/receiving media","If this happens during operation, check why the connection dropped — look for preceding \"matrix: connection lost\" logs and fix network/credentials","Guard download attempts: check client connectivity and skip or queue media when the client is unavailable","If it occurs during shutdown, ignore it or add a connectivity check before calling downloadMediaContent"],"exampleFix":"// before\ncontent, err := p.downloadMediaContent(ctx, ev.Content.URL)\n\n// after\nif p.getClient() == nil {\n    return fmt.Errorf(\"matrix: cannot download media, not connected\")\n}\ncontent, err := p.downloadMediaContent(ctx, ev.Content.URL)","handlingStrategy":"try-catch","validationCode":"if p.getClient() == nil {\n    // defer or skip media download\n}","typeGuard":"func mediaReady(p *Platform) bool { return p.getClient() != nil }","tryCatchPattern":"content, err := p.downloadMediaContent(ctx, url)\nif err != nil {\n    if err.Error() == \"not connected\" {\n        // queue for retry after reconnect\n        return\n    }\n    return err\n}","preventionTips":["Only process media events after the platform signals connected state","Add a reconnect-aware queue for media downloads","Monitor for \"matrix: connection lost\" events as the upstream cause"],"tags":["matrix","media-download","client-state","connectivity"],"backgroundTag":"connection-refused","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"}