{"record":{"id":"cd3f98fa5874885b","repo":"gastownhall/beads","slug":"failed-to-generate-unique-id-after-trying-lengths","errorCode":null,"errorMessage":"failed to generate unique ID after trying lengths %d-%d with 10 nonces each","messagePattern":"failed to generate unique ID after trying lengths (.+?)-(.+?) with 10 nonces each","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/wisps.go","lineNumber":85,"sourceCode":"\t}\n\n\tfor length := baseLength; length <= maxLength; length++ {\n\t\tfor nonce := 0; nonce < 10; nonce++ {\n\t\t\tcandidate := generateHashID(prefix, issue.Title, issue.Description, actor, issue.CreatedAt, length, nonce)\n\n\t\t\tvar count int\n\t\t\terr = tx.QueryRowContext(ctx, fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE id = ?`, table), candidate).Scan(&count) //nolint:gosec // G201\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to check for ID collision: %w\", err)\n\t\t\t}\n\n\t\t\tif count == 0 {\n\t\t\t\treturn candidate, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", fmt.Errorf(\"failed to generate unique ID after trying lengths %d-%d with 10 nonces each\", baseLength, maxLength)\n}\n\n// getAdaptiveIDLengthFromTable returns the adaptive ID length based on table size.\n//\n//nolint:gosec // G201: table is a hardcoded constant\nfunc getAdaptiveIDLengthFromTable(ctx context.Context, tx *sql.Tx, table, prefix string) int {\n\tvar count int\n\tif err := tx.QueryRowContext(ctx, fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE id LIKE ?`, table), prefix+\"%\").Scan(&count); err != nil {\n\t\treturn 4 // Default for wisps (small tables)\n\t}\n\n\tswitch {\n\tcase count < 100:\n\t\treturn 4\n\tcase count < 1000:\n\t\treturn 5\n\tcase count < 10000:\n\t\treturn 6","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/wisps.go#L67-L103","documentation":"Exhaustion error from generateIssueIDInTable: after trying every candidate length from baseLength to maxLength with 10 nonces each, every generated hash ID already existed in the table. This means the ID space for the given prefix/title inputs is saturated for this issue's content, an extraordinarily rare probabilistic event unless inputs are degenerate (e.g., many issues with identical title/description/actor/timestamp).","triggerScenarios":"Creating an issue when all hash-ID candidates across all supported lengths and 10 nonces per length collide with existing rows; practically only with huge tables, or batch creation of issues with identical content and CreatedAt.","commonSituations":"Import scripts creating thousands of near-identical issues with the same timestamp/actor; a clock froze so CreatedAt is constant across a bulk import; extremely large databases shrinking the effective ID space.","solutions":["Retry creation — with distinct timestamps or a nonce-advancing retry a free ID is almost always found","For bulk imports, vary CreatedAt/title or stagger inserts so hash inputs differ","Check whether a bug is producing constant hash inputs (same actor + frozen clock)","If the table is genuinely enormous, report/raise the adaptive ID length ceiling"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// avoid degenerate inputs: ensure distinct CreatedAt per issue in bulk imports\nif issue.CreatedAt.IsZero() || lastCreatedAt.Equal(issue.CreatedAt) && lastTitle == issue.Title {\n    issue.CreatedAt = issue.CreatedAt.Add(time.Second)\n}","typeGuard":null,"tryCatchPattern":"id, err := store.CreateIssue(ctx, issue)\nif err != nil && strings.Contains(err.Error(), \"failed to generate unique ID\") {\n    // perturb inputs and retry once\n    issue.CreatedAt = issue.CreatedAt.Add(time.Second)\n    id, err = store.CreateIssue(ctx, issue)\n}","preventionTips":["Stagger CreatedAt/titles in bulk import scripts so hash inputs differ","Never freeze timestamps across large batched creates","Monitor table size; very large databases narrow the ID space","If it reproduces with normal data, report as a bug in hash input construction"],"tags":["id-generation","collision","database","go"],"backgroundTag":"id-generation-exhausted","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}