{"record":{"id":"e43bfd3cfcc66b51","repo":"gastownhall/beads","slug":"wisp-not-found-s-e43bfd","errorCode":null,"errorMessage":"wisp not found: %s","messagePattern":"wisp not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/bulk_ops.go","lineNumber":337,"sourceCode":"\t\tEventType: \"renamed\",\n\t\tActor:     actor,\n\t\tOldValue:  str(oldID),\n\t\tNewValue:  str(newID),\n\t})\n}\n\nfunc updateWispIDInTx(ctx context.Context, tx *sql.Tx, oldID, newID string, issue *types.Issue, actor string) error {\n\tnow := time.Now().UTC()\n\tresult, err := tx.ExecContext(ctx, `\n\t\tUPDATE wisps\n\t\tSET id = ?, title = ?, description = ?, design = ?, acceptance_criteria = ?, notes = ?, updated_at = ?\n\t\tWHERE id = ?\n\t`, newID, issue.Title, issue.Description, issue.Design, issue.AcceptanceCriteria, issue.Notes, now, oldID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"update wisp ID: %w\", err)\n\t}\n\tif rows, _ := result.RowsAffected(); rows == 0 {\n\t\treturn fmt.Errorf(\"wisp not found: %s\", oldID)\n\t}\n\n\tif err = InsertDerivedEvent(ctx, tx, \"wisp_events\", AuxEvent{\n\t\tIssueID:   newID,\n\t\tEventType: \"renamed\",\n\t\tActor:     actor,\n\t\tOldValue:  str(oldID),\n\t\tNewValue:  str(newID),\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn UpdateWispIDInDependenciesInTx(ctx, tx, oldID, newID)\n}\n\n// FindWispDependentsRecursiveInTx walks wisp_dependencies to find all transitive\n// dependents of the given IDs.\nfunc FindWispDependentsRecursiveInTx(ctx context.Context, tx DBTX, ids []string) (map[string]bool, error) {","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/bulk_ops.go#L319-L355","documentation":"The wisp rename UPDATE affected zero rows: no wisp with oldID existed in the wisps table even though IsActiveWispInTx initially routed the rename there. The library surfaces this as \"wisp not found\" and aborts the transaction with no changes.","triggerScenarios":"Calling UpdateIssueIDInTx where oldID was detected as an active wisp but the `UPDATE wisps ... WHERE id = oldID` matched nothing — the wisp was reaped/compacted between the check and the update, or the ID was typed incorrectly.","commonSituations":"Race with wisp compaction (wisp promoted to a real issue or deleted concurrently); stale ID from another machine before sync; typo in the ID passed to `bd rename`.","solutions":["Re-fetch the item by ID to determine whether it is now an issue, a wisp, or gone, then retry accordingly.","Verify the exact ID (typos, case) before renaming.","Sync latest state from remote (bd dolt pull / sync) and retry.","Handle this as a transient race: retry the whole rename operation once."],"exampleFix":"// before\nstore.UpdateIssueID(ctx, wispID, newID, issue, actor) // wisp reaped concurrently -> not found\n// after\nif err := refreshAndRename(ctx, store, wispID, newID); err != nil {\n    var nf *NotFoundError\n    if errors.As(err, &nf) { return refreshAndRename(ctx, store, wispID, newID) } // retry after re-check\n    return err\n}","handlingStrategy":"try-catch","validationCode":"iss, err := store.GetIssue(ctx, oldID)\nif err != nil || iss == nil {\n    return fmt.Errorf(\"id %s no longer exists (wisp reaped or typo); refresh state\", oldID)\n}","typeGuard":null,"tryCatchPattern":"err := store.UpdateIssueID(ctx, oldID, newID, issue, actor)\nif err != nil && strings.HasPrefix(err.Error(), \"wisp not found:\") {\n    // wisp was compacted/promoted between check and update: re-resolve and retry once\n    return refreshAndRetry(ctx, store, oldID, newID)\n}","preventionTips":["Treat wisp renames as racy with compaction; re-fetch just before renaming.","Sync remote state before operating on wisp IDs.","Retry once on not-found before surfacing to the user."],"tags":["database","not-found","wisp","rename"],"backgroundTag":"issue-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}