{"record":{"id":"bff4adb8eec20df8","repo":"chenhg5/cc-connect","slug":"bridge-invalid-preview-handle","errorCode":null,"errorMessage":"bridge: invalid preview handle","messagePattern":"bridge: invalid preview handle","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/bridge.go","lineNumber":574,"sourceCode":"\tcase handle := <-ch:\n\t\treturn newBridgeReplyCtx(a, rc.SessionKey, handle), nil\n\tcase <-time.After(10 * time.Second):\n\t\ta.previewMu.Lock()\n\t\tdelete(a.previewRequests, refID)\n\t\ta.previewMu.Unlock()\n\t\treturn nil, fmt.Errorf(\"bridge: preview_ack timeout\")\n\tcase <-ctx.Done():\n\t\ta.previewMu.Lock()\n\t\tdelete(a.previewRequests, refID)\n\t\ta.previewMu.Unlock()\n\t\treturn nil, ctx.Err()\n\t}\n}\n\nfunc (bp *BridgePlatform) DeletePreviewMessage(ctx context.Context, previewHandle any) error {\n\trc, ok := previewHandle.(*bridgeReplyCtx)\n\tif !ok {\n\t\treturn fmt.Errorf(\"bridge: invalid preview handle\")\n\t}\n\ta := bp.server.getAdapter(rc.Platform)\n\tif a == nil || !a.capabilities[\"delete_message\"] {\n\t\treturn ErrNotSupported\n\t}\n\treturn bp.server.sendToAdapter(rc.Platform, map[string]any{\n\t\t\"type\":           \"delete_message\",\n\t\t\"session_key\":    rc.SessionKey,\n\t\t\"preview_handle\": rc.ReplyCtx,\n\t})\n}\n\nfunc (bp *BridgePlatform) StartTyping(ctx context.Context, replyCtx any) (stop func()) {\n\trc, ok := replyCtx.(*bridgeReplyCtx)\n\tif !ok {\n\t\treturn func() {}\n\t}\n\ta := bp.server.getAdapter(rc.Platform)","sourceCodeStart":556,"sourceCodeEnd":592,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/bridge.go#L556-L592","documentation":"DeletePreviewMessage requires the previewHandle to be the concrete *bridgeReplyCtx type that RequestPreviewMessage returned. This error is thrown when the handle is nil or of any other type, because the bridge cannot recover the platform and reply coordinates needed to route a delete_message command.","triggerScenarios":"Calling BridgePlatform.DeletePreviewMessage with nil, with a handle obtained from a different platform adapter, or with a deserialized/reconstructed map[string]any instead of the *bridgeReplyCtx pointer issued by RequestPreviewMessage.","commonSituations":"Storing handles in JSON (e.g. persisting state to disk or a DB) and passing the decoded generic value back; passing a handle from another Platform implementation; passing nil after a failed preview request.","solutions":["Use the exact *bridgeReplyCtx value returned by RequestPreviewMessage — never re-serialize or copy it into another type.","Check the handle is non-nil and comes from the same BridgePlatform/server instance that created it.","If handles must be persisted, persist an identifier and re-request the preview rather than reconstructing the handle object.","Guard the call with a type assertion and skip/log when the assertion fails instead of passing a bad handle through."],"exampleFix":"// before\nvar h any = storedPreviewHandleFromJSON\nerr := p.DeletePreviewMessage(ctx, h)\n// after\nrc, ok := storedPreviewHandle.(*core.BridgeReplyCtx) // keep original pointer type\nif !ok { return fmt.Errorf(\"no valid preview handle\") }\nerr := p.DeletePreviewMessage(ctx, rc)","handlingStrategy":"type-guard","validationCode":"func canDeletePreview(h any) bool {\n    _, ok := h.(*core.BridgeReplyCtx)\n    return ok\n}","typeGuard":"func asPreviewHandle(h any) (*core.BridgeReplyCtx, bool) {\n    rc, ok := h.(*core.BridgeReplyCtx)\n    return rc, ok\n}","tryCatchPattern":"rc, ok := handle.(*core.BridgeReplyCtx)\nif !ok {\n    return fmt.Errorf(\"preview handle unavailable (type %T)\", handle)\n}\nif err := p.DeletePreviewMessage(ctx, rc); err != nil {\n    slog.Warn(\"delete preview failed\", \"err\", err)\n}","preventionTips":["Treat preview handles as opaque in-memory values; never serialize them to JSON or a DB","Always keep the exact pointer returned by RequestPreviewMessage","Nil-check the handle before use, especially after a failed preview request","Don't share handles across different BridgePlatform instances or adapters"],"tags":["bridge","type-assertion","preview","invalid-argument"],"backgroundTag":"type-mismatch","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"}