gastownhall/beads · error
Failed to update %s: %v
Error message
Failed to update %s: %v
What it means
In doPull (internal/tracker/engine.go:534), when pulling an issue that already exists locally, beads wraps the update in a storage transaction (RunInIssueLifecycleTransaction -> applyPullIssueUpdate) applying field updates and labels. If the transaction fails, the engine warns with the local issue ID, increments stats.Errors, and continues with the next issue. The sync is not aborted; the failed issue simply is not updated.
Source
Thrown at internal/tracker/engine.go:534
e.msg("[dry-run] Would update local issue: %s - %s", extIssue.Identifier, ui.SanitizeForTerminal(extIssue.Title))
stats.Updated++
} else {
e.msg("[dry-run] Would import: %s - %s", extIssue.Identifier, ui.SanitizeForTerminal(extIssue.Title))
stats.Created++
}
continue
}
if existing != nil {
updates := buildPullIssueUpdates(existing, conv.Issue, ref)
if raw, ok := marshalTrackerMetadata(extIssue.Metadata); ok {
updates["metadata"] = raw
}
if err := e.Store.RunInIssueLifecycleTransaction(ctx, fmt.Sprintf("bd: pull update %s", existing.ID), func(tx storage.IssueLifecycleTransaction) error {
return applyPullIssueUpdate(ctx, tx, existing.ID, updates, conv.Issue.Labels, e.Actor)
}); err != nil {
e.warn("Failed to update %s: %v", existing.ID, err)
stats.Errors++
if pulledIDs != nil {
pulledIDs[existing.ID] = true
}
continue
}
stats.Updated++
if pulledIDs != nil {
pulledIDs[existing.ID] = true
}
} else {
// Create new issue
conv.Issue.ExternalRef = strPtr(ref)
if raw, ok := marshalTrackerMetadata(extIssue.Metadata); ok {
conv.Issue.Metadata = raw
}
if err := e.Store.CreateIssue(ctx, conv.Issue, e.Actor); err != nil {
e.warn("Failed to create issue for %s: %v", extIssue.Identifier, err)View on GitHub (pinned to 71377f2769)
Solutions
- Read the `%v` detail to identify the failing constraint (lock, uniqueness, invalid field, schema).
- Ensure no other bd process holds the DB; retry the pull after concurrent commands finish.
- Fix the offending remote/local data (e.g. invalid status or metadata the local schema cannot accept).
- Run pending migrations / `bd doctor` if the schema may be out of date after an upgrade.
- Re-run the pull; issues whose updates failed are retried since they were not synced successfully.
Example fix
// before: concurrent process holds a write lock Failed to update bd-123: database is locked (5) (SQLITE_BUSY) // after: finish/close the concurrent bd process, then bd sync # update succeeds, stats.Updated incremented for bd-123
Defensive patterns
Strategy: retry
Validate before calling
// before running sync, ensure no other bd process holds the DB and it is writable: bd doctor # or: check no concurrent `bd` runs; test write access to the .beads database
Try / catch
// doPull continues past the failure; verify via returned stats and re-run:
stats, err := eng.Sync(ctx, opts)
if err != nil { log.Fatalf("sync: %v", err) }
if stats.Errors > 0 {
time.Sleep(2 * time.Second)
if _, err := eng.Sync(ctx, opts); err != nil { log.Printf("retry sync failed: %v", err) }
} Prevention
- Avoid running multiple bd commands concurrently on the same repository.
- Keep the beads storage schema migrated after upgrades (`bd migrate`/`bd doctor`).
- Monitor disk space on the machine hosting the database.
- Re-run sync whenever stats.Errors > 0.
When it happens
Trigger: Running a pull/sync where a remote issue maps to an existing local issue and the storage update fails — DB locked or closed, constraint violation (e.g. invalid status/type value, unparseable metadata JSON from the tracker), uniqueness conflict on external_ref or ID, or the lifecycle transaction rejects a field transition.
Common situations: Concurrent `bd` processes contending for the same database (lock timeouts); tracker metadata containing values that violate local storage constraints; schema mismatch after a beads version upgrade without migration; disk-full or corrupted Dolt/sqlite state.
Related errors
- database not available: %w
- resolve custom issue types: %w
- failed to update issue: %w
- recompute is_blocked after status change for %s: %w
- Failed to update %s during reimport: %v
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f5738a7cb368ae13.
Report an issue: GitHub.