{"record":{"id":"467e33c9489ecc6c","repo":"gastownhall/beads","slug":"delete-resolve-ids-w-467e33","errorCode":null,"errorMessage":"delete: resolve ids: %w","messagePattern":"delete: resolve ids: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/uow/deleter.go","lineNumber":99,"sourceCode":"// issueops.Deleter promises that a dry run refuses exactly where the real run\n// refuses.\nfunc deleteInUOW(ctx context.Context, uw UnitOfWork, req publicops.DeleteRequest) (publicops.DeleteResult, error) {\n\tissueUC := uw.IssueUseCase()\n\tresult := publicops.DeleteResult{DryRun: req.DryRun}\n\n\t// The existence probe comes FIRST, so a request naming a typo reports the\n\t// typo rather than whatever the graph says about the ids that resolved. It\n\t// keeps the ROWS rather than a set of ids, because the version precondition\n\t// below needs their RowVersion and re-reading them for it would be a second\n\t// read of the same rows in the same transaction.\n\tpresent := make(map[string]*types.Issue, len(req.IDs))\n\tfor _, load := range []func(context.Context, []string) ([]*types.Issue, error){\n\t\tissueUC.GetIssuesByIDs,\n\t\tissueUC.GetWispsByIDs,\n\t} {\n\t\trows, err := load(ctx, req.IDs)\n\t\tif err != nil {\n\t\t\treturn publicops.DeleteResult{}, fmt.Errorf(\"delete: resolve ids: %w\", err)\n\t\t}\n\t\tfor _, row := range rows {\n\t\t\tif row != nil {\n\t\t\t\tpresent[row.ID] = row\n\t\t\t}\n\t\t}\n\t}\n\tvar missing []string\n\tfor _, id := range req.IDs {\n\t\tif present[id] == nil {\n\t\t\tmissing = append(missing, id)\n\t\t}\n\t}\n\tif len(missing) > 0 {\n\t\treturn publicops.DeleteResult{}, &publicops.NotFoundError{IDs: missing}\n\t}\n\n\t// The version precondition, between the existence probe and the dependents","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/deleter.go#L81-L117","documentation":"The unit-of-work delete path failed to resolve the requested ids into rows: loading via GetIssuesByIDs or GetWispsByIDs returned an error. The delete aborts before any dependent checks or removal happen, so no data was changed.","triggerScenarios":"deleteInUOW iterates the two loaders with the request's id list and one of the backing queries fails — DB error, connection loss, or a storage-layer failure while fetching issues or wisps by id.","commonSituations":"Database unavailable or restarted mid-request; corrupt index; transient Dolt transaction error during bulk delete requests.","solutions":["Retry the delete once the wrapped DB error's cause is fixed","Check the inner error for connection/timeout problems and restore DB connectivity","Verify the ids are well-formed; malformed ids should fail validation earlier, so an error here is usually infrastructural"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"for _, id := range req.IDs {\n    if !strings.HasPrefix(id, \"bd-\") { return fmt.Errorf(\"malformed id %q\", id) }\n}","typeGuard":null,"tryCatchPattern":"res, err := deleteInUOW(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"delete: resolve ids\") {\n    // transient DB failure likely; retry after backoff\n    return retryWithBackoff(func() error { return deleteInUOW(ctx, req) })\n}","preventionTips":["Verify DB connectivity before large delete operations","Validate ids before submitting delete requests","Monitor database health; this failure is usually infrastructural","Apply backoff on wrapped DB errors rather than altering input"],"tags":["database","delete","id-resolution"],"backgroundTag":"id-resolution-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}