Skip to content

Instantly share code, notes, and snippets.

@PabloLION
Last active March 5, 2026 19:55
Show Gist options
  • Select an option

  • Save PabloLION/827beb43e766a3f3bb28b12baf9715ed to your computer and use it in GitHub Desktop.

Select an option

Save PabloLION/827beb43e766a3f3bb28b12baf9715ed to your computer and use it in GitHub Desktop.
Beads: Dolt server port collision — detection & repair guide (GH#2372)

Beads: Dolt server port collision — detection & repair guide (GH#2372)

Beads: Dolt Server Port Collision — Detection & Repair Guide

If you use beads across multiple projects on the same machine, versions v0.56.1–v0.58.0 may silently connect to the wrong project's Dolt server, causing cross-project issue leakage.

Related: GH#2372

The Problem

Beads v0.56.1 removed embedded Dolt mode, requiring all installations to use a network Dolt server. The port resolution logic in DefaultConfig() (internal/doltserver/doltserver.go) consults multiple sources, some of which are git-tracked:

  1. BEADS_DOLT_SERVER_PORT env var
  2. metadata.jsonDoltServerPort (designed to be committed)
  3. config.yaml / global config → dolt.port
  4. .beads/dolt-server.portnot in .beads/.gitignore
  5. Gas Town fixed port: 3307 (if GT_ROOT set)
  6. DerivePort(beadsDir) — FNV-32a hash, range [13307–14306]

When two projects resolve to the same port, the bd client connects to whichever Dolt server happens to be running — with zero identity verification. Issues from one project silently appear in another.

Symptoms

  • bd list returns issues with the wrong prefix (e.g., you see ch- issues in a project that uses bd-)
  • Issue counts don't match what you expect
  • Issues you never created appear in your tracker
  • The problem is intermittent — it depends on which server grabbed the port first

Detection

Step 1: Check for Foreign Prefixes

Run this in each project directory:

python3 -c "
import json
from collections import Counter
prefixes = Counter()
with open('.beads/issues.jsonl') as f:
    for line in f:
        line = line.strip()
        if not line: continue
        issue = json.loads(line)
        prefix = issue['id'].rsplit('-', 1)[0]
        prefixes[prefix] += 1
for prefix, count in prefixes.most_common():
    print(f'  {prefix}: {count}')
"

If you see prefixes that don't belong to this project, you have contamination.

Step 2: Check Backend Type

cat .beads/metadata.json

If "database": "dolt", the project is using the Dolt backend.

Step 3: Compare JSONL vs Dolt (if on Dolt backend)

# Count in JSONL
wc -l .beads/issues.jsonl

# Count in Dolt
cd .beads/dolt
dolt sql -q "SHOW DATABASES" -r csv
# Find your database name (not dolt/information_schema/mysql)
dolt sql -q "SELECT COUNT(*) FROM <db_name>.issues" -r csv

If counts differ, one source has data the other doesn't.

Repair: Rollback to SQLite

The fix is to abandon the Dolt backend entirely and return to SQLite, using JSONL as the source of truth. Do not attempt to fix this by switching to a different Dolt version — any Dolt network server setup carries the same port collision risk.

Recommended version for repair: v0.49.6 — the last release before v0.50 introduced Dolt as the default backend. v0.49.6 has zero Dolt code paths, so it cannot accidentally interact with a contaminated .beads/dolt/ directory during the recovery process. bd doctor won't nag about Dolt migration, and the import/export cycle is purely SQLite + JSONL.

Note: the maintainers recommend v0.55.4 for normal use (last stable embedded-Dolt version — no network server, no port collision risk). After completing this repair, you can upgrade to v0.55.4 or later once the port isolation fixes in epic bd-109c ship. v0.49.6 is specifically recommended here as a clean recovery environment.

You can install it from GitHub releases or via Homebrew with a versioned formula (see the Homebrew installing older versions guide).

Step 1: Preserve Dolt-Only Data

If Dolt has issues not in JSONL (check Step 3), export them first:

cd .beads/dolt
dolt sql -q "SELECT * FROM <db_name>.issues WHERE id NOT IN (<jsonl_ids>)" -r json

Append the exported issues to .beads/issues.jsonl.

Step 2: Remove Foreign Issues from JSONL

# Back up first
cp .beads/issues.jsonl .beads/issues.jsonl.backup

# Filter to keep only your prefix
python3 -c "
import json
MY_PREFIX = 'your-prefix'  # Change this
kept = []
with open('.beads/issues.jsonl') as f:
    for line in f:
        line = line.strip()
        if not line: continue
        issue = json.loads(line)
        if issue['id'].startswith(MY_PREFIX + '-'):
            kept.append(line)
with open('.beads/issues.jsonl', 'w') as f:
    for line in kept:
        f.write(line + '\n')
print(f'Kept {len(kept)} issues')
"

Step 3: Switch Metadata to SQLite

# Update metadata.json
echo '{"database": "beads.db", "jsonl_export": "issues.jsonl"}' > .beads/metadata.json

Step 4: Remove Dolt Artifacts

rm -rf .beads/dolt/
rm -f .beads/dolt-server.lock .beads/dolt-server.log .beads/dolt-server.port .beads/dolt-server.pid

Step 5: Downgrade bd to v0.49.6

v0.49.6 is the last version without Dolt as default. On v0.50+, bd doctor will constantly suggest migrating to Dolt, and some code paths may re-introduce Dolt artifacts.

# Download from GitHub releases
# https://github.com/steveyegge/beads/releases/tag/v0.49.6
bd version  # should show 0.49.6

Step 6: Rebuild SQLite from JSONL

# If you have custom issue types, register them first:
# bd config set types.custom "type1,type2,type3"

bd import -i .beads/issues.jsonl

# Fix database version if needed:
bd migrate

Step 7: Verify

bd doctor     # should show 0 errors
bd list --status=open

Notes

  • JSONL is the durable format. In our experience, some Dolt databases were completely empty despite being the configured backend. The git-tracked JSONL survived.
  • The contamination is silent. No error, no warning — just wrong data. The only way to notice is recognizing foreign issue prefixes.
  • Worktrees share JSONL. If you use git worktrees, all worktrees of the same repo share .beads/issues.jsonl. Fix once in the main worktree.
  • Kill leftover Dolt processes after rollback:
    pkill -f "dolt sql-server"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment