{"record":{"id":"97ffffbf5f305b45","repo":"actualbudget/actual","slug":"there-is-already-a-report-named-item-name","errorCode":null,"errorMessage":"There is already a report named ${item.name}","messagePattern":"There is already a report named (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/reports/app.ts","lineNumber":146,"sourceCode":"  }\n\n  //default return: item was found but does not match current name\n  return true;\n}\n\nasync function createReport(report: CustomReportEntity) {\n  const reportId = uuidv4();\n  const item: CustomReportEntity = {\n    ...report,\n    id: reportId,\n  };\n  if (!item.name) {\n    throw new Error('Report name is required');\n  }\n\n  const nameExists = await reportNameExists(item.name, item.id ?? '', true);\n  if (nameExists) {\n    throw new Error('There is already a report named ' + item.name);\n  }\n\n  // Create the report here based on the info\n  await db.insertWithSchema('custom_reports', reportModel.fromJS(item));\n\n  return reportId;\n}\n\nasync function updateReport(item: CustomReportEntity) {\n  if (!item.name) {\n    throw new Error('Report name is required');\n  }\n\n  if (!item.id) {\n    throw new Error('Report recall error');\n  }\n\n  const nameExists = await reportNameExists(item.name, item.id, false);","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/reports/app.ts#L128-L164","documentation":"Thrown by createReport when reportNameExists finds an existing non-deleted (tombstone = 0) custom_reports row with the same name. Names act as unique identifiers for custom reports among living reports, so creating a duplicate name is rejected with this message.","triggerScenarios":"Calling createReport with a name that matches any existing report in the custom_reports table (case-exact match via SQL name = ?), regardless of the new report's id — e.g. re-running an import script, duplicating a report through the API, or retrying a create after a partial failure.","commonSituations":"Idempotency-lacking automation that re-imports reports on every run; users/API scripts recreating a report that already exists; testing scripts that insert the same sample report repeatedly; renaming one report to collide with another before create.","solutions":["Pick a unique name — check existing names first via getReports and suffix if taken","Wrap the call and catch the error, then fall back to creating with a suffixed name ('Name (2)')","For re-runnable imports, look up the existing report by name and update it (updateReport) instead of creating","Delete the existing duplicate report if it is stale and recreation is intended"],"exampleFix":"// before\nawait app.createReport({ name: existingName, ...report });\n// after\nconst existing = reports.find(r => r.name === report.name);\nif (existing) {\n  await app.updateReport({ ...report, id: existing.id });\n} else {\n  await app.createReport(report);\n}","handlingStrategy":"try-catch","validationCode":"const existing = await app.getReports();\nif (existing.some(r => r.name === newReport.name)) {\n  newReport.name = `${newReport.name} (${new Date().toISOString().slice(0, 10)})`;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await app.createReport(report);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('There is already a report named ')) {\n    await app.createReport({ ...report, name: report.name + ' (2)' });\n  } else {\n    throw err;\n  }\n}","preventionTips":["Look up existing reports via getReports and de-duplicate names before creating","Make import scripts idempotent: update by name instead of blindly creating","Suffix generated names with a timestamp or uuid in automation","Reuse reportNameExists-equivalent checks in caller code when batch-inserting"],"tags":["custom-reports","duplicate","validation"],"backgroundTag":"duplicate-name-conflict","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}