fix: disambiguate CONFLICT errors in registerProject by inspecting the SQLite UNIQUE constraint column

Previously a single "that name or URL" message was thrown regardless of which
column violated uniqueness. Now the catch block inspects the error string from
SQLite to emit a name-specific or url-specific message, with a generic fallback
when neither column can be identified.

Adds vitest tests covering all four scenarios: name conflict, url conflict,
unknown column conflict, and non-UNIQUE error passthrough.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas May
2026-03-06 14:37:21 +01:00
parent d867a5f397
commit 8f4fa2a233
2 changed files with 107 additions and 2 deletions

View File

@@ -30,11 +30,24 @@ export function projectProcedures(publicProcedure: ProcedureBuilder) {
...(input.defaultBranch && { defaultBranch: input.defaultBranch }),
});
} catch (error) {
const msg = (error as Error).message;
const msg = (error as Error).message ?? '';
if (msg.includes('UNIQUE') || msg.includes('unique')) {
if (msg.includes('projects.name') || (msg.includes('name') && !msg.includes('url'))) {
throw new TRPCError({
code: 'CONFLICT',
message: 'A project with this name already exists',
});
}
if (msg.includes('projects.url') || msg.includes('url')) {
throw new TRPCError({
code: 'CONFLICT',
message: 'A project with this URL already exists',
});
}
// fallback: neither column identifiable
throw new TRPCError({
code: 'CONFLICT',
message: `A project with that name or URL already exists`,
message: 'A project with this name or URL already exists',
});
}
throw error;