{"record":{"id":"246f2637c07d3f82","repo":"gastownhall/beads","slug":"delete-remote-tracking-ref-s-w","errorCode":null,"errorMessage":"delete remote-tracking ref %s: %w","messagePattern":"delete remote-tracking ref (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/remoterefs.go","lineNumber":44,"sourceCode":"}\n\n// PruneRemoteRefs deletes every cached remote-tracking ref and returns the\n// names deleted. After a history squash (Flatten/Compact) these refs still\n// anchor the pre-squash commit chain, so DOLT_GC treats the entire old history\n// as reachable and reclaims nothing (bd-agctw). Pruning is safe on a squashed\n// workspace: the refs are local caches only — nothing is deleted on the remote\n// itself — and the next push or fetch re-creates them at the new tip.\n//\n// On error, the returned slice holds the refs deleted before the failure.\nfunc PruneRemoteRefs(ctx context.Context, db DBConn) ([]string, error) {\n\trefs, err := ListRemoteRefs(ctx, db)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar pruned []string\n\tfor _, name := range refs {\n\t\tif _, err := db.ExecContext(ctx, \"CALL DOLT_BRANCH('-D', '-r', ?)\", name); err != nil {\n\t\t\treturn pruned, fmt.Errorf(\"delete remote-tracking ref %s: %w\", name, err)\n\t\t}\n\t\tpruned = append(pruned, name)\n\t}\n\treturn pruned, nil\n}\n\n// ListTags returns the names of all Dolt tags, sorted by name. Tags anchor\n// history the same way remote-tracking refs do, but they are user-created, so\n// callers should surface them rather than delete them.\nfunc ListTags(ctx context.Context, db DBConn) ([]string, error) {\n\trows, err := db.QueryContext(ctx, \"SELECT tag_name FROM dolt_tags ORDER BY tag_name\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"list tags: %w\", err)\n\t}\n\tdefer rows.Close()\n\n\tvar tags []string\n\tfor rows.Next() {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/remoterefs.go#L26-L62","documentation":"PruneRemoteRefs deletes each cached remote-tracking ref via CALL DOLT_BRANCH('-D', '-r', name). This error wraps a failure of that stored-procedure call for a specific ref, with the ref name embedded in the message. It reports which ref could not be deleted; the returned slice contains the refs already deleted before the failure.","triggerScenarios":"Calling PruneRemoteRefs when CALL DOLT_BRANCH('-D', '-r', ?) fails for a ref: the ref vanished concurrently, the Dolt engine rejects the delete, the connection breaks mid-loop, or the context is cancelled partway through the batch.","commonSituations":"Another process fetched/pushed and removed or recreated the ref while pruning; Dolt server-side constraint or permission error on DOLT_BRANCH; network drop or timeout during a long pruning loop; embedded Dolt refusing the call in a read-only session.","solutions":["Read the ref name in the error message and check whether it still exists (SELECT name FROM dolt_remote_branches); refs deleted concurrently can simply be skipped and the call retried.","Retry PruneRemoteRefs — it is idempotent per ref and the error tells you where to resume (refs before it were already pruned).","If the context was cancelled, re-run with a fresh context; already-deleted refs will not error on a second pass.","Check Dolt engine logs for the underlying DOLT_BRANCH failure if retries keep failing (permissions, read-only mode, or engine bug)."],"exampleFix":"// before\npruned, err := versioncontrolops.PruneRemoteRefs(ctx, db)\nif err != nil { return err } // treats partial success as total failure\n// after: handle partial results and retry remaining refs\npruned, err := versioncontrolops.PruneRemoteRefs(ctx, db)\nif err != nil {\n    log.Printf(\"pruned %d refs before failure: %v\", len(pruned), err)\n    // retry is safe: remaining refs are still listed and deleted\n    _, err = versioncontrolops.PruneRemoteRefs(ctx, db)\n}","handlingStrategy":"retry","validationCode":"rows, err := db.QueryContext(ctx, \"SELECT name FROM dolt_remote_branches ORDER BY name\")\nif err != nil {\n    return err\n}\n// snapshot refs immediately before pruning to reduce concurrent-modification risk","typeGuard":null,"tryCatchPattern":"pruned, err := versioncontrolops.PruneRemoteRefs(ctx, db)\nif err != nil {\n    // pruned holds refs deleted before the failure; retry is safe and resumes where it stopped\n    log.Printf(\"partial prune (%d done): %v\", len(pruned), err)\n    time.Sleep(retryDelay)\n    _, err = versioncontrolops.PruneRemoteRefs(ctx, db)\n}","preventionTips":["Treat PruneRemoteRefs as idempotent and retry on failure — already-deleted refs are skipped on the next pass.","Avoid running concurrent fetch/push while pruning remote-tracking refs.","Give the pruning loop a generous context timeout for many refs.","Inspect the ref name in the error message to diagnose engine-side DOLT_BRANCH failures."],"tags":["dolt","stored-procedure","batch-partial-failure"],"backgroundTag":"stored-procedure-call-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}