Skip to content

Duplicate-key error detection duplicated across 4 routes with inconsistent matching #89

@dobby-coder

Description

@dobby-coder

Problem

"Did this insert fail because the unique constraint tripped?" is detected in four places, each slightly differently. The members route in particular only matches `unique` and misses the `duplicate key` substring postgres emits on its main error message — so a unique-violation under that wording becomes a 500 to the user instead of a friendly 409.

File Pattern
`src/routes/(admin)/admin/organizations/+page.server.ts:104` helper `isDuplicateKeyError` — checks `duplicate key` OR `unique` on message + cause
`src/routes/(admin)/admin/organizations/[id]/+page.server.ts:184` inline regex `/duplicate key|unique/i` on message + cause
`src/routes/(portal)/portal/members/+page.server.ts:34` `err.message.includes('unique')` only — misses `duplicate key` path
`src/routes/(marketing)/register/+page.server.ts:81-83` inline includes on message + cause

Suggested fix

Extract a single helper (e.g. `src/lib/server/services/_errors.ts`):

```ts
export function isUniqueViolation(err: unknown): boolean {
if (!(err instanceof Error)) return false;
const msg = err.message ?? '';
const cause = (err as { cause?: { message?: string } }).cause?.message ?? '';
const hay = `${msg}\n${cause}`.toLowerCase();
return hay.includes('duplicate key') || hay.includes('unique');
}
```

Then replace the four call sites. The members route gets correct `duplicate key` coverage for free.

Why this matters

The members-route gap is the user-visible part: portal users adding a duplicate member email today may see an unexpected 500 instead of the intended 409 message, depending on which postgres error path fires.

Test plan

  • Unit test the helper against shaped postgres error objects (both `duplicate key` wording and `unique constraint` wording on `message` and on `cause.message`).
  • Verify all four call sites still produce the same form-error shape.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions