Skip to content

Festival/edition slug editing: dashes unusable while typing, no uniqueness check, generic conflict error #497

Description

@chiptus

Problem

Found while testing FestivalDialog's edit flow (pre-existing, not introduced by #495). All three affect both FestivalDialog.tsx and FestivalEditionManagement.tsx, since they share the same slug helpers and mutation-error pattern.

1. Can't type a dash into the slug field

handleSlugChange runs sanitizeSlug/generateSlug (src/lib/slug.ts) on every keystroke via the controlled input's onChange:

function handleSlugChange(slug: string) {
  const cleanSlug = sanitizeSlug(slug);
  setFormData((prev) => ({ ...prev, slug: cleanSlug }));
  ...
}

generateSlug strips leading/trailing hyphens:

.replace(/^-+|-+$/g, "")

Typing "boom-festival" character by character passes through the state "boom-" after the 5th keystroke — at that instant the hyphen is trailing, so it gets stripped immediately, snapping the field back to "boom". The next keystroke ("f") then appends directly to "boom", not "boom-", so a hyphen typed in the middle of a slug can never survive a normal sequence of keystrokes. (The only way to get a hyphenated slug into the field today is to paste the whole value at once, which sidesteps the per-keystroke sanitization.)

2. No client-side uniqueness check

handleSubmit in both dialogs validates only presence and format (isValidSlug) before submitting:

if (!isValidSlug(formData.slug)) {
  toast({ title: "Error", description: "Please enter a valid slug", ... });
  return;
}

There's no query against existing festivals/editions to warn about a taken slug before hitting submit — the only enforcement is the DB's unique constraint (festivals_slug_unique, festival_editions_slug_festival_unique), discovered only after a failed save.

3. Generic error message on a real unique-constraint conflict

useUpdateFestivalMutation's (and the edition equivalent's) onError doesn't discriminate the failure cause:

onError: (error) => {
  console.error("Error updating festival:", error);
  toast({ title: "Error", description: "Failed to update festival", variant: "destructive" });
},

A slug conflict (Postgres 23505 unique_violation) surfaces the same generic "Failed to update festival" as any other failure, giving the user no indication of what to actually fix.

Related

#467 already designs the right treatment for this exact class of problem — explicit slug field, format validation, a client-side uniqueness pre-check, and mapping a constraint-violation error to a friendly message — but scoped to the sets/artists edit forms only. This issue is the same treatment needed for the festival/festival-edition edit forms, which #467 doesn't cover.

The dash-typing bug (#1) is a new finding not mentioned in #467's design — worth accounting for there too, since #467 also plans to reuse isValidSlug/sanitizeSlug from src/lib/slug.ts for its new slug field, which would inherit the same per-keystroke corruption unless the field sets its value on blur/paste rather than sanitizing every keystroke.

Suggested fix

  • Sanitize on blur (or debounce/only strip trailing hyphens on submit), not on every keystroke — so a hyphen typed mid-string survives.
  • Add a lightweight uniqueness query (scoped appropriately — global for festivals, per-festival for editions) run before submit, surfaced as a form/toast warning.
  • In both useUpdateFestivalMutation's and the edition mutation's onError, inspect the Postgrest error code (23505) and show a specific "This slug is already taken" message instead of the generic fallback.

Context

Reported during review of PR #495 (fix-157/finish-mutate-migration), which touches the same files for an unrelated mutateAsync→mutate migration but didn't introduce these bugs.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions