{"record":{"id":"6e1b9e4a2450037e","repo":"gastownhall/beads","slug":"failed-to-record-push-hash-for-s-v","errorCode":null,"errorMessage":"Failed to record push hash for %s: %v","messagePattern":"Failed to record push hash for (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/tracker/engine.go","lineNumber":920,"sourceCode":"\tcurrent := e.pushCacheValue(issue, externalRef)\n\tif current == \"\" {\n\t\treturn false\n\t}\n\tstored, err := e.Store.GetLocalMetadata(ctx, e.pushHashKey(issue.ID))\n\treturn err == nil && stored != \"\" && stored == current\n}\n\n// recordPushHash persists the current content-and-target fingerprint for issue\n// so subsequent pushes can short-circuit via storedPushHashMatches. No-op when\n// ContentHash is unset or returns \"\", or when the target is empty. Never called\n// during dry-run.\nfunc (e *Engine) recordPushHash(ctx context.Context, issue *types.Issue, externalRef string) {\n\th := e.pushCacheValue(issue, externalRef)\n\tif h == \"\" {\n\t\treturn\n\t}\n\tif err := e.Store.SetLocalMetadata(ctx, e.pushHashKey(issue.ID), h); err != nil {\n\t\te.warn(\"Failed to record push hash for %s: %v\", issue.ID, err)\n\t}\n}\n\nfunc (e *Engine) doPush(ctx context.Context, opts SyncOptions, skipIDs, forceIDs map[string]bool) (*PushStats, error) {\n\tctx, span := syncTracer.Start(ctx, \"tracker.push\",\n\t\ttrace.WithAttributes(\n\t\t\tattribute.String(\"sync.tracker\", e.Tracker.DisplayName()),\n\t\t\tattribute.Bool(\"sync.dry_run\", opts.DryRun),\n\t\t),\n\t)\n\tdefer span.End()\n\n\tstats := &PushStats{}\n\n\t// BuildStateCache hook: pre-cache workflow states once before the loop.\n\t// Stored on Engine so tracker adapters can call ResolveState() during push.\n\te.stateCache = nil\n\tif e.PushHooks != nil && e.PushHooks.BuildStateCache != nil {","sourceCodeStart":902,"sourceCodeEnd":938,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/tracker/engine.go#L902-L938","documentation":"recordPushHash (internal/tracker/engine.go:920) is called by doPush after an issue is pushed, to store the pushed content hash via Store.SetLocalMetadata under pushHashKey(issue.ID). That hash is the sync's dirty-check baseline — on the next push, issues whose hash matches are considered unchanged and skipped. If the metadata write fails, the engine warns and returns; the push itself already succeeded, but the issue will look 'unpushed' next time.","triggerScenarios":"Any `bd push`/sync that completes an issue push and then fails the SetLocalMetadata write — DB write lock held by another bd process, storage closed/unavailable, disk full, or metadata-key constraint failures in the local-metadata table.","commonSituations":"Concurrent `bd` commands racing on the same database; read-only or full disk; the storage connection dropped mid-sync; embedding the engine with a storage backend that errors on local-metadata writes.","solutions":["Read the `%v` detail; if it is a lock error, close other concurrent bd processes and re-run.","Re-run `bd push` (or a no-op sync) — the hash write is retried for any issue whose stored hash is still missing.","Check disk space and that the database file is writable.","If the backend persistently fails metadata writes, run `bd doctor` to diagnose the storage layer.","Worst case, force re-push (e.g. --force) so hashes are recomputed and recorded after storage is healthy."],"exampleFix":"// before: parallel bd sync holds the write lock\nFailed to record push hash for bd-123: database is locked (5)\n// after: wait for the other process to exit, then\nbd sync  # bd-123 hash recorded; subsequent pushes skip it as unchanged","handlingStrategy":"retry","validationCode":"// before pushing, confirm storage is writable and uncontended:\nbd doctor   # and ensure no concurrent bd processes are running","typeGuard":null,"tryCatchPattern":"// recordPushHash only warns; detect degraded sync state and recover:\nif strings.Contains(warnOutput, \"Failed to record push hash\") {\n    time.Sleep(2 * time.Second)\n    exec.Command(\"bd\", \"push\").Run() // re-run so hashes are written; unchanged issues re-pushed once\n}","preventionTips":["Serialize bd commands; never run push while another sync is active.","Keep adequate disk space and verify DB file permissions.","Re-run push after any storage-level warning so hash bookkeeping converges.","Use --force only after storage health is confirmed, to rebuild hashes."],"tags":["storage","push","cache","sync-state"],"backgroundTag":"push-hash-write-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}