{"record":{"id":"f1806adb91930c1f","repo":"can1357/oh-my-pi","slug":"bank-name-already-exists","errorCode":null,"errorMessage":"Bank '${name}' already exists","messagePattern":"Bank '(.+?)' already exists","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/mnemopi/src/core/banks.ts","lineNumber":36,"sourceCode":"\treadonly db_path: string;\n\treadonly dbSizeBytes: number;\n\treadonly db_size_bytes: number;\n}\n\nexport class BankManager {\n\treadonly dataDir: string;\n\treadonly banksDir: string;\n\n\tconstructor(dataDir?: string) {\n\t\tthis.dataDir = dataDir ?? configuredDataDir();\n\t\tthis.banksDir = join(this.dataDir, \"banks\");\n\t\tmkdirSync(this.banksDir, { recursive: true });\n\t}\n\n\tcreateBank(name: string): string {\n\t\tthis.validateName(name);\n\t\tconst bankDir = join(this.banksDir, name);\n\t\tif (existsSync(bankDir)) throw new ValueError(`Bank '${name}' already exists`);\n\t\tmkdirSync(bankDir, { recursive: true });\n\t\tconst dbPath = join(bankDir, DB_FILENAME);\n\t\tconst db = openDatabase(dbPath);\n\t\tcloseQuietly(db);\n\t\treturn dbPath;\n\t}\n\tdeleteBank(name: string, force = false): boolean {\n\t\tthis.validateName(name);\n\t\tif (name === \"default\" && !force) throw new ValueError(\"Cannot delete 'default' bank without force=True\");\n\t\tconst bankDir = join(this.banksDir, name);\n\t\tif (!existsSync(bankDir)) return false;\n\t\trmSync(bankDir, { recursive: true, force: true });\n\t\treturn true;\n\t}\n\tlistBanks(): string[] {\n\t\tconst banks: string[] = [\"default\"];\n\t\tif (existsSync(this.banksDir)) {\n\t\t\tfor (const entry of readdirSync(this.banksDir, { withFileTypes: true })) {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/core/banks.ts#L18-L54","documentation":"`BankManager.createBank()` refuses to create a bank whose on-disk directory already exists under the banks data directory. Each bank gets its own directory plus SQLite database, so an existing directory means the bank is already initialized; creating again would clobber it.","triggerScenarios":"Calling `createBank(name)` (or the `bank create` CLI command) when `<dataDir>/banks/<name>/` already exists — i.e. the bank was created previously and not deleted.","commonSituations":"Re-running an init/setup script twice, choosing a name that collides with an existing bank, teammate-created bank in a shared data dir, idempotency attempt that assumed create was upsert-like.","solutions":["Check existence first with `getBankStats(name)` or `listBanks()` and skip creation if it already exists.","Use a different bank name.","Delete the unwanted bank with `deleteBank(name, true)` before recreating (destructive).","Catch the ValueError and treat the existing bank as the target."],"exampleFix":"// before\nconst dbPath = banks.createBank(\"work\");\n// after\nconst stats = banks.getBankStats(\"work\");\nconst dbPath = stats.exists ? banks.getBankDbPath(\"work\") : banks.createBank(\"work\");","handlingStrategy":"try-catch","validationCode":"import { existsSync } from \"node:fs\";\nconst bankDir = join(dataDir, \"banks\", name);\nconst alreadyExists = existsSync(bankDir);","typeGuard":"null","tryCatchPattern":"try {\n  dbPath = banks.createBank(name);\n} catch (err) {\n  if (err instanceof ValueError && err.message.includes(\"already exists\")) {\n    dbPath = banks.getBankDbPath(name); // reuse existing\n  } else throw err;\n}","preventionTips":["Check getBankStats(name).exists before creating.","Make init scripts idempotent (create-if-missing).","Use listBanks() to pick unique names.","Never blindly re-run setup without existence checks."],"tags":["duplicate","bank","already-exists"],"backgroundTag":"resource-already-exists","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}