{"record":{"id":"ee273572dccb705e","repo":"gastownhall/beads","slug":"commit-pending-before-pull-w","errorCode":null,"errorMessage":"commit pending before pull: %w","messagePattern":"commit pending before pull: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/embeddeddolt/version_control.go","lineNumber":528,"sourceCode":"// unchanged. Routing every verb through the one resolver also narrows the\n// window around withPeerAuth's mutation of that process-wide pair: a verb\n// operating on a peer-backed remote now reads it holding federationEnvMutex,\n// where before it read it holding no lock at all.\n\nfunc (s *EmbeddedDoltStore) Push(ctx context.Context) error {\n\treturn s.withPeerAuth(ctx, defaultRemote, func(user string) error {\n\t\treturn s.withMutatingDBConn(ctx, func(db versioncontrolops.DBConn) error {\n\t\t\treturn vcPush(ctx, db, defaultRemote, s.branch, user)\n\t\t})\n\t})\n}\n\nfunc (s *EmbeddedDoltStore) Pull(ctx context.Context) error {\n\t// GH#2474 / bd-578h9.2: auto-commit pending changes before pull, matching\n\t// server-mode pullFromRemote and PullFrom. Leftovers from a crashed\n\t// command would otherwise make the merge refuse to start.\n\tif _, err := s.CommitPending(ctx, \"beads\"); err != nil {\n\t\treturn fmt.Errorf(\"commit pending before pull: %w\", err)\n\t}\n\tpreHead := s.preMergeHead(ctx)\n\terr := s.withPeerAuth(ctx, defaultRemote, func(user string) error {\n\t\treturn s.withMutatingPinnedDBConn(ctx, func(db versioncontrolops.DBConn) error {\n\t\t\treturn vcPull(ctx, db, defaultRemote, s.branch, user)\n\t\t})\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn s.recomputeBlockedAfterPull(ctx, preHead)\n}\n\n// PullWithStrategy implements storage.StrategicPuller for `bd dolt pull\n// --strategy` (#4992 part 2). Identical to Pull except conflicts the\n// auto-resolver declines are resolved with strategy instead of aborting the\n// merge for the operator; see versioncontrolops.PullWithStrategy.\nfunc (s *EmbeddedDoltStore) PullWithStrategy(ctx context.Context, strategy string) error {","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/embeddeddolt/version_control.go#L510-L546","documentation":"EmbeddedDoltStore.Pull auto-commits pending working-set changes before pulling (GH#2474 / bd-578h9.2), because leftovers from a crashed command would make the incoming merge refuse to start. This error wraps any failure from that pre-pull CommitPending call — the pull itself was never attempted. The wrapped error carries the underlying commit failure (which may itself be ErrCommitIndeterminate).","triggerScenarios":"Calling Pull when CommitPending(ctx, \"beads\") fails — a Dolt commit error (driver failure, indeterminate commit, database locked/corrupt) occurs while auto-committing dirty tables before vcPull runs.","commonSituations":"Recovering after a crashed bd command left a dirty working set; database lock contention from a concurrent bd process; Dolt storage errors during the auto-commit; an indeterminate commit from a prior crash surfacing now.","solutions":["Inspect the wrapped cause: if it is ErrCommitIndeterminate, first read the current state/HEAD to see whether the pre-commit actually landed before retrying.","Resolve any concurrent bd process holding the database, then retry the pull.","Run `bd doctor` if you suspect leftover state from a crashed command, then re-run `bd pull`.","Commit or stash the pending changes manually (bd commit / dolt status) and retry the pull.","If the database is corrupt, restore from remote or re-init the embedded store before pulling."],"exampleFix":"// before: retrying pull immediately on error\nif err := store.Pull(ctx); err != nil {\n    return store.Pull(ctx)\n}\n\n// after: check indeterminate pre-commit state first\nif err := store.Pull(ctx); err != nil {\n    if errors.Is(err, storage.ErrCommitIndeterminate) {\n        // pre-commit may have landed; verify then retry once\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isPrePullCommitFailure(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"commit pending before pull:\")\n}","tryCatchPattern":"if err := store.Pull(ctx); err != nil {\n    if isPrePullCommitFailure(err) {\n        // failure is LOCAL auto-commit, not the remote pull.\n        if errors.Is(err, storage.ErrCommitIndeterminate) {\n            // verify local HEAD/state, reconcile, then retry once\n        }\n    }\n    return err\n}","preventionTips":["Commit or clean pending changes before pulling instead of relying solely on auto-commit.","Run one bd process per database; lock contention here means another writer is active.","After a crash, reconcile state (`bd doctor`) before pulling.","Handle ErrCommitIndeterminate explicitly — the pre-commit may have landed despite the error."],"tags":["embeddeddolt","pull","auto-commit","version-control"],"backgroundTag":"pull-precommit-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}