{"record":{"id":"a422fcd8a32dbda9","repo":"chenhg5/cc-connect","slug":"matrix-client-not-available","errorCode":null,"errorMessage":"matrix: client not available","messagePattern":"matrix: client not available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/matrix/verification.go","lineNumber":202,"sourceCode":"\n\t// ConfirmSAS must run in a separate goroutine because onVerificationKey\n\t// holds activeTransactionsLock when calling showSAS, and ConfirmSAS\n\t// also acquires the same non-reentrant mutex.\n\tgo func() {\n\t\thelper := vc.platform.getVerificationHelper()\n\t\tif helper == nil {\n\t\t\treturn\n\t\t}\n\t\tif err := helper.ConfirmSAS(context.Background(), txnID); err != nil {\n\t\t\tslog.Error(\"matrix: confirm SAS failed\", \"txn_id\", txnID, \"error\", err)\n\t\t}\n\t}()\n}\n\nfunc (p *Platform) initVerification(ctx context.Context, ch *cryptohelper.CryptoHelper) error {\n\tclient := p.getClient()\n\tif client == nil {\n\t\treturn fmt.Errorf(\"matrix: client not available\")\n\t}\n\n\t// Wrap the client's actual HTTP transport. We must use client.Client directly\n\t// (not p.httpClient) because cryptohelper.Init() may have replaced client.Client\n\t// with a new http.Client instance.\n\tif client.Client == nil {\n\t\treturn fmt.Errorf(\"matrix: client http.Client is nil\")\n\t}\n\tbase := client.Client.Transport\n\tif base == nil {\n\t\tbase = http.DefaultTransport\n\t}\n\tclient.Client.Transport = &encryptingTransport{base: base, p: p}\n\tslog.Info(\"matrix: transport wrapped for verification encryption\")\n\n\tcallbacks := &verificationCallbacks{platform: p}\n\thelper := verificationhelper.NewVerificationHelper(client, ch.Machine(), nil, callbacks, false, false, true)\n","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/matrix/verification.go#L184-L220","documentation":"initVerification aborts E2EE device-verification setup with \"matrix: client not available\" when getClient() returns nil. Initializing the verification helper requires an authenticated Matrix client to register event handlers and access the crypto machine. Without a live client, verification cannot be set up.","triggerScenarios":"initE2EE calls initVerification before the client is assigned (startup ordering issue), or after clearClient() nulled it (connection lost), so getClient() == nil at the start of initVerification.","commonSituations":"E2EE enabled in config but the initial login/sync failed, leaving the client nil; a race between connection teardown and E2EE initialization during a reconnect cycle.","solutions":["Make sure Start() successfully created the client before initE2EE runs — check earlier login errors","Verify Matrix credentials/homeserver reachability so the client is actually established","Order the startup sequence so E2EE/verification init happens after client creation","If triggered by a reconnect race, guard initVerification with a connectivity check or retry after reconnect"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if p.getClient() == nil {\n    // postpone E2EE init until the client exists\n}","typeGuard":"func e2eeReady(p *Platform) bool { return p.getClient() != nil }","tryCatchPattern":"if err := p.initVerification(ctx, ch); err != nil {\n    if strings.Contains(err.Error(), \"client not available\") {\n        // retry after (re)connect\n        return nil\n    }\n    return err\n}","preventionTips":["Initialize E2EE strictly after successful client login","Assert client != nil in startup sequencing tests","Re-run verification init on every reconnect"],"tags":["matrix","e2ee","verification","client-state"],"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"}