{"record":{"id":"bef36ed84977c317","repo":"gastownhall/beads","slug":"failed-to-check-for-id-collision-w-bef36e","errorCode":null,"errorMessage":"failed to check for ID collision: %w","messagePattern":"failed to check for ID collision: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/helpers.go","lineNumber":207,"sourceCode":"\t// Default hash-based ID generation\n\tbaseLength, err := GetAdaptiveIDLengthTx(ctx, tx, table, prefix)\n\tif err != nil {\n\t\tbaseLength = 6\n\t}\n\n\tmaxLength := 8\n\tif baseLength > maxLength {\n\t\tbaseLength = maxLength\n\t}\n\n\tfor length := baseLength; length <= maxLength; length++ {\n\t\tfor nonce := 0; nonce < 10; nonce++ {\n\t\t\tcandidate := idgen.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)\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// IsCounterModeTx checks whether issue_id_mode=counter is configured.\nfunc IsCounterModeTx(ctx context.Context, tx DBTX) (bool, error) {\n\tvar idMode string\n\terr := tx.QueryRowContext(ctx, \"SELECT value FROM config WHERE `key` = ?\", \"issue_id_mode\").Scan(&idMode)\n\tif err != nil && err != sql.ErrNoRows {\n\t\treturn false, fmt.Errorf(\"failed to read issue_id_mode config: %w\", err)\n\t}","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/helpers.go#L189-L225","documentation":"GenerateIssueIDInTable probes for a collision-free hash ID by running SELECT COUNT(*) against the issue table for each candidate. This error means that collision-check query itself failed (not that a collision was found), so ID generation must abort. The underlying driver error is preserved via %w.","triggerScenarios":"Calling GenerateIssueIDInTable (via assignCreateIssueIDInTx) when the issue table doesn't exist, the transaction was invalidated by an earlier error, the connection dropped mid-query, or a lock timeout occurs while counting rows for id = ?","commonSituations":"Running against a database where the issues table was dropped or renamed; schema migration incomplete after upgrade; embedded DB locked by another process; context canceled during a long create storm.","solutions":["Inspect the wrapped error to distinguish missing-table (schema issue) from lock/timeout issues","Run schema migrations / bd doctor to confirm the issue table exists in this DB","Retry the create once the conflicting transaction or lock is released","If using counter mode, verify issue_id_mode config; counter mode skips hash probing entirely"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm the target table exists before ID generation\nvar n int\nif err := tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM information_schema.tables WHERE table_name = ?`, table).Scan(&n); err != nil || n == 0 {\n\treturn fmt.Errorf(\"table %s missing: run migrations\", table)\n}","typeGuard":null,"tryCatchPattern":"id, err := GenerateIssueIDInTable(ctx, tx, issue, actor)\nif err != nil {\n\tif errors.Is(err, context.Canceled) || isLockTimeout(err) {\n\t\t// retry once with fresh transaction after backoff\n\t}\n\treturn fmt.Errorf(\"generate issue id: %w\", err)\n}","preventionTips":["Keep the ID-generation and insert in the same short transaction to minimize lock windows","Run migrations before app start so the issue table exists","Avoid context timeouts shorter than expected query latency on large tables","Monitor for other processes holding write locks on embedded databases"],"tags":["database","id-generation","sql","transaction"],"backgroundTag":"id-collision-check-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}