{"record":{"id":"28cffe6ed7b3866c","repo":"gastownhall/beads","slug":"db-update-s-read-old-issue-w","errorCode":null,"errorMessage":"db: Update %s: read old issue: %w","messagePattern":"db: Update (.+?): read old issue: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/issue.go","lineNumber":174,"sourceCode":"\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ttable := pickIssueTable(opts.UseWispsTable)\n\n\tmergeOps := issueops.HasMergeOps(updates)\n\n\t// Read the prior row once. Status and merge updates need it for their\n\t// transaction-local resolution, and every update uses it to suppress true\n\t// no-ops before changing row_lock or recording an event.\n\toldIssue, err := r.Get(ctx, id, opts)\n\tif err != nil {\n\t\tif errors.Is(err, sql.ErrNoRows) {\n\t\t\treturn fmt.Errorf(\"db: Update %s: %w\", id, sql.ErrNoRows)\n\t\t}\n\t\treturn fmt.Errorf(\"db: Update %s: read old issue: %w\", id, err)\n\t}\n\n\t// Resolve read-merge-write operation keys (issueops.OpMergeMetadata,\n\t// OpSetMetadata, OpUnsetMetadata, OpAppendNotes) into concrete column\n\t// values inside the mutation transaction, mirroring the embedded path\n\t// (issueops.updateIssueInTx). Callers must pass the OPERATION, never a\n\t// value pre-merged from an earlier read: this runner is a Dolt sql-server\n\t// session where FOR UPDATE is a parse-only no-op, so a stale-snapshot merge\n\t// is only made safe by Dolt's commit-time conflict detection plus the\n\t// caller redoing the whole unit of work on a serialization failure — and\n\t// that redo re-runs this in-transaction resolution against the winner's\n\t// committed row.\n\tif mergeOps {\n\t\tresolved, err := issueops.ResolveMergeOps(oldIssue, updates)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"db: Update %s: %w\", id, err)\n\t\t}\n\t\tupdates = resolved","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/issue.go#L156-L192","documentation":"Wraps any non-ErrNoRows failure from r.Get when Update reads the prior row prior to applying changes. This distinguishes real read failures (connection, schema, context) from the missing-row case handled separately. The update aborts before any mutation.","triggerScenarios":"Calling Update when the internal Get fails: connection loss, context canceled/cancelled deadline, corrupted row failing scan, missing table on the non-wisp path, or lock contention blocking the read inside a transaction.","commonSituations":"Database restarted mid-operation; context timeout too short for the read; schema drift after a failed migration; row with unexpected NULL columns breaking scan.","solutions":["Inspect the wrapped cause from r.Get (driver error, context error, scan error)","Run migrations if schema/table issues are indicated","Increase the context timeout or retry on transient errors","Check row integrity if scan errors appear (NULLs in NOT-NULL-assumed columns)"],"exampleFix":"// before\nerr := repo.Update(ctx, id, updates, actor, opts)\n// after\nctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()\nif err := repo.Update(ctx, id, updates, actor, opts); err != nil {\n    if !errors.Is(err, sql.ErrNoRows) { log.Warnf(\"read failure: %v\", err) }\n}","handlingStrategy":"retry","validationCode":"ctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()\nif err := ctx.Err(); err != nil { return err }","typeGuard":"func isReadFailure(err error) bool {\n    return err != nil && !errors.Is(err, sql.ErrNoRows)\n}","tryCatchPattern":"err := retry(3, backoff, func() error {\n    err := repo.Update(ctx, id, updates, actor, opts)\n    if err != nil && errors.Is(err, sql.ErrNoRows) { return stopRetry(err) }\n    if err != nil && !isTransientDBErr(err) { return stopRetry(err) }\n    return err\n})","preventionTips":["Keep context deadlines generous for read-modify-write updates","Ensure schema consistency after migrations","Monitor DB connectivity and restarts","Check row data integrity if scan errors recur"],"tags":["database","issue","read","update"],"backgroundTag":"db-read-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}