Files
beads/.beads/BUG-FOUND-getNextID.md
2025-10-14 01:19:11 -07:00

2.4 KiB

BUG FOUND: getNextID() uses alphabetical MAX instead of numerical

Location

internal/storage/sqlite/sqlite.go:60-84, function getNextID()

The Bug

err := db.QueryRow("SELECT MAX(id) FROM issues").Scan(&maxID)

This uses alphabetical MAX on the text id column, not numerical MAX.

Impact

When you have bd-1 through bd-10:

  • Alphabetical sort: bd-1, bd-10, bd-2, bd-3, ... bd-9
  • MAX(id) returns "bd-9" (alphabetically last)
  • nextID is calculated as 10
  • Creating a new issue tries to use bd-10, which already exists
  • Result: UNIQUE constraint failed

Reproduction

# After creating bd-1 through bd-10
./bd create "Test issue" -t task -p 1
# Error: failed to insert issue: UNIQUE constraint failed: issues.id

The Fix

Option 1: Cast to integer in SQL (BEST)

SELECT MAX(CAST(SUBSTR(id, INSTR(id, '-') + 1) AS INTEGER)) FROM issues WHERE id LIKE 'bd-%'

Option 2: Pad IDs with zeros

  • Change ID format from "bd-10" to "bd-0010"
  • Alphabetical and numerical order match
  • Breaks existing IDs

Option 3: Query all IDs and find max in Go

  • Less efficient but more flexible
  • Works with any ID format

Option 1 with proper prefix handling:

func getNextID(db *sql.DB) int {
	// Get prefix from config (default "bd")
	var prefix string
	err := db.QueryRow("SELECT value FROM config WHERE key = 'issue_prefix'").Scan(&prefix)
	if err != nil || prefix == "" {
		prefix = "bd"
	}

	// Find max numeric ID for this prefix
	var maxNum sql.NullInt64
	query := `
		SELECT MAX(CAST(SUBSTR(id, LENGTH(?) + 2) AS INTEGER))
		FROM issues
		WHERE id LIKE ? || '-%'
	`
	err = db.QueryRow(query, prefix, prefix).Scan(&maxNum)
	if err != nil || !maxNum.Valid {
		return 1
	}

	return int(maxNum.Int64) + 1
}

Workaround for Now

Manually specify IDs when creating issues:

# This won't work because auto-ID fails:
./bd create "Title" -t task -p 1

# Workaround - manually calculate next ID:
./bd list | grep -oE 'bd-[0-9]+' | sed 's/bd-//' | sort -n | tail -1
# Then add 1 and create with explicit ID in code

Or fix the bug first before continuing!

This bug is EXACTLY the kind of distributed ID collision problem that bd-9 is designed to solve! But we should also fix the root cause.

Created Issue

Should create: "Fix getNextID() to use numerical MAX instead of alphabetical"

  • Type: bug
  • Priority: 0 (critical - blocks all new issue creation)
  • Blocks: bd-9 (can't create child issues)