{"record":{"id":"d761795d4dc758bb","repo":"gastownhall/beads","slug":"check-s-for-issue-q-w","errorCode":null,"errorMessage":"check %s for issue %q: %w","messagePattern":"check (.+?) for issue %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/create_only_guard.go","lineNumber":27,"sourceCode":"\t\"github.com/steveyegge/beads/internal/storage\"\n)\n\n// EnsureIssueIDAvailableInTx serializes same-shard creates and rejects occupied IDs.\nfunc EnsureIssueIDAvailableInTx(ctx context.Context, tx DBTX, id string) error {\n\tif tx == nil {\n\t\treturn fmt.Errorf(\"ensure issue ID available: transaction is nil\")\n\t}\n\tif id == \"\" {\n\t\treturn fmt.Errorf(\"ensure issue ID available: ID is empty\")\n\t}\n\tkey := issueCreateCoordinationKey(id)\n\tif _, err := tx.ExecContext(ctx, \"REPLACE INTO local_metadata (`key`, value) VALUES (?, ?)\", key, strconv.FormatInt(FreshRowLock(), 10)); err != nil {\n\t\treturn fmt.Errorf(\"coordinate issue create: %w\", err)\n\t}\n\tfor _, table := range []string{\"issues\", \"wisps\"} {\n\t\tvar count int\n\t\tif err := tx.QueryRowContext(ctx, \"SELECT COUNT(*) FROM \"+table+\" WHERE id = ?\", id).Scan(&count); err != nil {\n\t\t\treturn fmt.Errorf(\"check %s for issue %q: %w\", table, id, err)\n\t\t}\n\t\tif count > 0 {\n\t\t\treturn fmt.Errorf(\"%w: %s\", storage.ErrAlreadyExists, id)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc issueCreateCoordinationKey(id string) string {\n\tsum := sha256.Sum256([]byte(id))\n\tshard := uint16(sum[0])<<4 | uint16(sum[1])>>4\n\treturn fmt.Sprintf(\"issue-create/v1/%03x\", shard)\n}\n","sourceCodeStart":9,"sourceCodeEnd":41,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/create_only_guard.go#L9-L41","documentation":"EnsureIssueIDAvailableInTx failed while counting rows for the ID in the issues or wisps tables. This is the existence-probe step of the guard; a scan/query failure means the storage backend errored, not that the ID is taken (a taken ID yields the distinct ErrAlreadyExists wrap at index 3466).","triggerScenarios":"QueryRowContext(\"SELECT COUNT(*) FROM issues|wisps WHERE id = ?\") returns a driver error — corrupted schema, missing table, connection drop mid-transaction.","commonSituations":"Migrations not applied (table absent); Dolt/driver-level failures during heavy concurrent imports; DB connectivity loss.","solutions":["Read the wrapped error to identify which table and what driver error occurred","Verify the schema is current (apply pending migrations)","Retry with a fresh transaction and healthy connection"],"exampleFix":"// before\n// assume table exists\n// after\n// run migrations first, then retry create in a new tx","handlingStrategy":"retry","validationCode":"// ensure schema is migrated before issuing creates\n// SELECT COUNT(*) FROM issues LIMIT 1; SELECT COUNT(*) FROM wisps LIMIT 1;","typeGuard":null,"tryCatchPattern":"if err := CreateIssueInTxWithResult(ctx, tx, issue); err != nil {\n    if strings.HasPrefix(err.Error(), \"check \") {\n        cause := errors.Unwrap(err)\n        // migrate/reconnect, then retry in a new tx\n    }\n    return err\n}","preventionTips":["Run migrations as part of deployment","Watch for driver connectivity errors in logs","Avoid mixing DDL and create workloads mid-flight"],"tags":["database","query","transaction","create"],"backgroundTag":"issue-existence-check-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}