gastownhall/beads · error
read wisp %s: %w
Error message
read wisp %s: %w
What it means
operationIssue first tries the wisp plane via GetWisp; if the wisp read fails with an error that is neither ErrNotFound nor a no-rows error, the operation aborts and this error wraps the underlying failure. It signals an unexpected storage-layer failure while reading the ephemeral (wisp) copy of an issue, not a simple 'does not exist' case.
Source
Thrown at internal/storage/uow/issue_operations.go:502
func updateHistoryEntry(request publicops.UpdateRequest, changed bool) string {
if !changed && request.Claim && reflect.DeepEqual(request.Patch, publicops.IssuePatch{}) {
return ""
}
return storageissueops.HistoryEntry(request.Provenance, "update issue")
}
// operationIssue resolves id to the row an operation is about. Both planes are
// searched unless issuePlaneOnly restricts it, in which case a wisp id is a
// miss rather than an ephemeral row to operate on. Every call runs inside the
// operation's own transaction.
func operationIssue(ctx context.Context, uw UnitOfWork, id string, issuePlaneOnly bool) (*types.Issue, bool, error) {
if !issuePlaneOnly {
issue, err := uw.IssueUseCase().GetWisp(ctx, id)
if err == nil && issue != nil {
return issue, true, nil
}
if err != nil && !errors.Is(err, publicops.ErrNotFound) && !dberrors.IsNoRows(err) {
return nil, false, fmt.Errorf("read wisp %s: %w", id, err)
}
}
issue, err := uw.IssueUseCase().GetIssue(ctx, id)
if err != nil {
if errors.Is(err, publicops.ErrNotFound) || dberrors.IsNoRows(err) {
return nil, false, fmt.Errorf("%w: issue %s", publicops.ErrNotFound, id)
}
return nil, false, err
}
if issue == nil {
return nil, false, fmt.Errorf("%w: issue %s", publicops.ErrNotFound, id)
}
return issue, false, nil
}
func validationError(err error) error {
if errors.Is(err, publicops.ErrValidation) {
return errView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause (errors.Unwrap / %w chain) to identify the underlying storage error
- Verify database connectivity and that the Dolt DB is healthy (bd doctor / driver health)
- Retry the operation if the failure was transient (connection reset, lock timeout)
- Confirm the storage schema matches the expected version; run migrations if behind
- If it persists, file an issue with the wrapped error and operation context
Example fix
// before: treating any wisp error as fatal
if err != nil { return err }
// after: only abort on non-not-found errors, matching operationIssue semantics
if err != nil && !errors.Is(err, publicops.ErrNotFound) && !dberrors.IsNoRows(err) {
return fmt.Errorf("read wisp %s: %w", id, err)
}
// not-found falls through to the durable GetIssue read Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check database reachability before the operation
if err := db.PingContext(ctx); err != nil { return fmt.Errorf("storage unavailable: %w", err) } Try / catch
if _, _, err := op.OperationIssue(ctx, id); err != nil {
var nf *fmt.wrapError
if errors.Is(err, publicops.ErrNotFound) { /* fall back */ }
else if isTransient(err) { /* retry with backoff */ }
else { return fmt.Errorf("wisp read failed: %w", err) }
} Prevention
- Keep wisp and durable planes in sync (regular bd dolt push/pull)
- Monitor driver/database health before batch operations
- Distinguish sentinel errors (ErrNotFound, IsNoRows) from real failures in your retry logic
- Log the full wrapped error chain (using %w / errors.Unwrap) for diagnosis
When it happens
Trigger: Calling Update/Close/Reopen/hydrateIssueOperation when issuePlaneOnly is false and uw.IssueUseCase().GetWisp returns a genuine error (DB corruption, connection failure, driver error) rather than not-found.
Common situations: Dolt/driver connectivity problems, locked or corrupted database, schema drift between planes, or a bug in the wisp use case that returns a non-sentinel error during normal issue lookup flows.
Related errors
- not found
- load wisp labels: %w
- edge %d %s->%s: checking planned blocking cycle: %w
- reading existing dependencies for %s: %w
- CountOpenChildren %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b3262ff82ca9ea8e.
Report an issue: GitHub.