{"record":{"id":"bb674edba4b7a3f2","repo":"gastownhall/beads","slug":"determining-wisp-status-for-s-w","errorCode":null,"errorMessage":"determining wisp status for %s: %w","messagePattern":"determining wisp status for (.+?): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/mol_port.go","lineNumber":389,"sourceCode":"}\n\nfunc (w *uowMolWriter) isWisp(ctx context.Context, id string) (bool, error) {\n\tif w.wispIDs[id] {\n\t\treturn true, nil\n\t}\n\tif w.notWispIDs[id] {\n\t\treturn false, nil\n\t}\n\t_, err := w.uw.IssueUseCase().GetWisp(ctx, id)\n\tif err == nil {\n\t\tw.wispIDs[id] = true\n\t\treturn true, nil\n\t}\n\tif errors.Is(err, sql.ErrNoRows) {\n\t\tw.notWispIDs[id] = true\n\t\treturn false, nil\n\t}\n\treturn false, fmt.Errorf(\"determining wisp status for %s: %w\", id, err)\n}\n\nfunc (w *uowMolWriter) CreateIssue(ctx context.Context, issue *types.Issue, actor string) error {\n\tparams := domain.CreateIssueParams{Issue: issue, ExplicitID: issue.ID, Labels: issue.Labels}\n\tvar err error\n\tif issue.Ephemeral || issue.NoHistory {\n\t\t_, err = w.uw.IssueUseCase().CreateWisp(ctx, params, actor)\n\t\tif err == nil {\n\t\t\tw.wispIDs[issue.ID] = true\n\t\t}\n\t} else {\n\t\t_, err = w.uw.IssueUseCase().CreateIssue(ctx, params, actor)\n\t\tif err == nil {\n\t\t\tw.notWispIDs[issue.ID] = true\n\t\t}\n\t}\n\treturn err\n}","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/mol_port.go#L371-L407","documentation":"uowMolWriter.isWisp caches whether an issue ID is an ephemeral 'wisp' by calling GetWisp. If GetWisp returns an error that is neither success nor sql.ErrNoRows (i.e. a real storage failure, not 'not a wisp'), it wraps it as 'determining wisp status for <id>'. This guards against misclassifying storage errors as 'not a wisp'.","triggerScenarios":"Calling AddDependency, UpdateIssue, CloseIssue, or ClaimStepIfOpen on a uowMolWriter when the underlying GetWisp storage lookup fails with a non-not-found error: DB corruption, driver failure, context cancellation, or unexpected error types that don't map to sql.ErrNoRows.","commonSituations":"Storage driver returning a custom not-found error type that no longer matches sql.ErrNoRows (behavior change after driver/upgrade); locked or inaccessible Dolt database; context deadline exceeded during a long molecule operation.","solutions":["Read the wrapped cause to identify the real storage error","If a driver upgrade changed the not-found sentinel, map it to sql.ErrNoRows at the driver boundary (per the storage boundary policy)","Check database health and retry transient failures (bd doctor)","If caused by context cancellation, increase timeout or re-run the operation"],"exampleFix":"// before: driver returns custom ErrNotFound, isWisp treats it as a hard error\n_, err := w.uw.IssueUseCase().GetWisp(ctx, id)\n// after: normalize at the driver boundary so errors.Is(err, sql.ErrNoRows) works\nif errors.Is(err, driver.ErrNotFound) {\n\treturn nil, sql.ErrNoRows\n}","handlingStrategy":"try-catch","validationCode":"// probe wisp lookup before performing writes\nif _, err := uw.IssueUseCase().GetWisp(ctx, id); err != nil && !errors.Is(err, sql.ErrNoRows) {\n\treturn fmt.Errorf(\"storage unhealthy for %s: %w\", id, err)\n}","typeGuard":"func isWispLookupFailure(err error) bool {\n\treturn err != nil && !errors.Is(err, sql.ErrNoRows) && !errors.Is(err, context.Canceled)\n}","tryCatchPattern":"if err := writer.UpdateIssue(ctx, issue, actor); err != nil {\n\tif strings.Contains(err.Error(), \"determining wisp status\") {\n\t\t// underlying GetWisp failed; check storage, retry\n\t}\n\treturn err\n}","preventionTips":["Keep the storage driver's not-found errors normalized to sql.ErrNoRows at the driver boundary","Avoid long-running operations that hold a context near expiry while touching many IDs","Run bd doctor to verify DB health before bulk molecule mutations","Watch for driver upgrades that change sentinel error types"],"tags":["go","wisp","storage","wrapped-error"],"backgroundTag":"database-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}