Skip to content

Create does not reject duplicate bean IDs; collisions are near-certain at id_length 4 and beans check stays green#211

Description

@kahnpoint

Summary

Core.Create does not check whether a generated (or explicitly provided) bean ID already exists in the store. At the default id_length: 4 (36-char alphabet, ~1.7M space) collisions are near-certain at realistic store sizes, and each collision silently writes a second file that shadows the first: beans check stays green, while beans list/GraphQL collapse the two records into one.

Reproduction (CLI, v0.4.2)

mkdir -p store && cat > .beans.yml <<'YAML'
beans:
  path: store
  prefix: scroll-
  id_length: 4
YAML

python3 -c "
aliases = ' '.join(f'b{i}: createBean(input: {{title: \"Vol {i}\"}}) {{ id }}' for i in range(6000))
print('mutation { ' + aliases + ' }')" > bulk.graphql

beans query --json "$(cat bulk.graphql)" > /dev/null

ls store | sed 's/--.*//' | sort | uniq -d   # -> 13 duplicate IDs
beans check; echo "exit=$?"                  # -> exit=0

6000 creations produced 5987 unique IDs (13 duplicate groups). beans check exits 0 over the duplicated store.

Failing test (Go, against internal/beancore)

func TestCreateRejectsDuplicateID(t *testing.T) {
	dir := t.TempDir()
	core := newTestCore(t, dir) // existing test helper pattern

	a := &bean.Bean{ID: "scroll-dupe", Title: "First"}
	if err := core.Create(a); err != nil {
		t.Fatalf("first create failed: %v", err)
	}

	b := &bean.Bean{ID: "scroll-dupe", Title: "Second"}
	if err := core.Create(b); err == nil {
		t.Fatal("second create with the same ID succeeded; want duplicate-ID rejection")
	}
}

The second Create succeeds today: Create only generates an ID when b.ID == "" and then writes unconditionally (internal/beancore/core.go, c.beans[b.ID] = b + saveToDisk).

Suggested fix

Two parts, either independently valuable:

  1. Collision guard: in Create, if b.ID already exists (explicit or generated), either regenerate with a bounded retry loop or return an error. The explicit-ID case should always error.
  2. Check detection: beans check should fail when two files resolve to the same bean ID, so already-duplicated stores are discoverable.

Environment

  • beans 0.4.2 (670ecf3) built 2026-03-10, darwin/arm64, Homebrew cask
  • reproduced with ~3.2k real beans (33 duplicate groups found in the wild) and the synthetic run above

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions