{"record":{"id":"d7b9e84564a4c90f","repo":"gastownhall/beads","slug":"wisp-plane-membership-w","errorCode":null,"errorMessage":"wisp plane membership: %w","messagePattern":"wisp plane membership: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/export_source.go","lineNumber":335,"sourceCode":"\t}\n\n\treturn rel, nil\n}\n\n// WispPlaneIDs classifies by wisps-table membership through the plane-pinned\n// GetWispsByIDs read (row flags are NOT a substitute — see the exportSource\n// interface comment). A rig without the wisp tables has no wisp-plane rows,\n// mirroring the tolerance of the wisp-plane legs in LoadExportRelations.\nfunc (s *uowExportSource) WispPlaneIDs(ctx context.Context, ids []string) (map[string]bool, error) {\n\tif len(ids) == 0 {\n\t\treturn nil, nil\n\t}\n\twisps, err := s.uw.IssueUseCase().GetWispsByIDs(ctx, ids)\n\tif err != nil {\n\t\tif dberrors.IsTableNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"wisp plane membership: %w\", err)\n\t}\n\tset := make(map[string]bool, len(wisps))\n\tfor _, w := range wisps {\n\t\tset[w.ID] = true\n\t}\n\treturn set, nil\n}\n\n// mergeExportMap copies src entries into dst. The label/comment planes are\n// disjoint by ID (an issue lives in exactly one of issues/wisps), so a plain\n// overwrite-merge reassembles the classic partitioned loaders' single map.\nfunc mergeExportMap[V any](dst, src map[string]V) {\n\tfor k, v := range src {\n\t\tdst[k] = v\n\t}\n}\n","sourceCodeStart":317,"sourceCodeEnd":352,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/export_source.go#L317-L352","documentation":"This error wraps a failure from `IssueUseCase().GetWispsByIDs(ctx, ids)` inside WispPlaneIDs, which determines which of the given IDs are members of the wisp (closed/tombstoned) plane. A missing-table condition returns (nil, nil) — an empty set — by design; this error is only returned for real storage failures, aborting the operation.","triggerScenarios":"Calling WispPlaneIDs when GetWispsByIDs fails with a non-table-not-exist error: Dolt backend unreachable, SQL error filtering wisps by ID batch, cancelled context, or corrupt wisp/issue table.","commonSituations":"Export or compaction flows that consult wisp membership on a database whose wisp tables exist but are broken; Dolt server outage during a wisp-aware operation; timeouts on large ID batches.","solutions":["Inspect the wrapped cause; restore storage connectivity or restart the Dolt server","Run `bd doctor`/migrations if the wisp tables are corrupt or partially migrated","Retry the operation; transient cancellation/timeouts usually clear","If the driver's table-not-exist error isn't being recognized, upgrade so legacy rigs correctly resolve to an empty wisp set"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// no cheap pre-check; probe backend reachability before wisp-plane lookups\nif err := store.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"storage backend unreachable: %w\", err)\n}","typeGuard":"func isTableNotExist(err error) bool { return dberrors.IsTableNotExist(err) }","tryCatchPattern":"set, err := WispPlaneIDs(ctx, ids)\nif err != nil {\n    return fmt.Errorf(\"wisp plane membership: %w\", err)\n}","preventionTips":["Treat an empty result as legitimate for legacy rigs (missing tables return nil, nil)","Keep wisp tables healthy via migrations/`bd doctor` before wisp-aware operations","Use adequate context timeouts for large ID batches","Diagnose from the wrapped cause, not the wrapper message"],"tags":["go","wisps","storage","dolt","export"],"backgroundTag":"database-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}