Skip to content

fix: use .maybeSingle() in applications route to prevent 500 on not-found#444

Closed
tankgxy wants to merge 1 commit into
profullstack:masterfrom
tankgxy:fix/apps-route-maybe-single
Closed

fix: use .maybeSingle() in applications route to prevent 500 on not-found#444
tankgxy wants to merge 1 commit into
profullstack:masterfrom
tankgxy:fix/apps-route-maybe-single

Conversation

@tankgxy

@tankgxy tankgxy commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Two .single() calls in the applications route would throw 500 errors when looking up a non-existent gig or checking for existing applications. Changed both to .maybeSingle() so the null-check logic that follows actually works correctly.

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a correctness bug where .single() was used in two places where 0 rows is a valid, expected outcome. When no matching gig or duplicate application existed, .single() would return PGRST116 error + null data, causing the null-check guards to either misbehave or propagate unexpected errors. Replacing both with .maybeSingle() ensures a clean null is returned and the existing guards work as designed.

  • Gig lookup (line 49): .maybeSingle() means a missing gig_id now cleanly hits if (!gig) → 404 instead of potentially propagating a PGRST116 error.
  • Duplicate-application check (line 79): .maybeSingle() means the absence of an existing application no longer produces a spurious error, so new applications are correctly allowed through.

Confidence Score: 4/5

Safe to merge — the two changed calls are the correct fix for the described behaviour, and the remaining .single() on the insert is appropriate since an insert always yields exactly one row.

The core change is small, well-targeted, and correct. One remaining .single() on the profiles lookup (line 124) has the same 0-row exposure as the two calls that were fixed, and neither maybeSingle() call checks the error field, which can obscure real DB failures as misleading 404s. Both are non-blocking quality issues on a non-critical code path.

src/app/api/applications/route.ts — the profiles .single() on line 124 and the unhandled error fields on the two new .maybeSingle() calls are worth a second look.

Important Files Changed

Filename Overview
src/app/api/applications/route.ts Fixes two .single() → .maybeSingle() calls so 0-row results return null instead of a PGRST116 error, making the downstream null-checks work correctly. One .single() on the profiles lookup (line 124) and one on the insert (line 97) remain; the insert one is fine, but the profiles one has the same 0-row exposure.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Route as POST /api/applications
    participant DB as Supabase DB

    Client->>Route: "POST { gig_id, ... }"
    Route->>Route: Auth + rate-limit check
    Route->>DB: "SELECT gig WHERE id=gig_id .maybeSingle()"
    alt gig not found (null)
        DB-->>Route: "{ data: null, error: null }"
        Route-->>Client: 404 Gig not found
    else gig found
        DB-->>Route: "{ data: gig }"
        Route->>Route: "Check gig.status === active"
        Route->>Route: "Check gig.poster_id !== user.id"
        Route->>DB: SELECT application WHERE gig_id AND applicant_id .maybeSingle()
        alt already applied (non-null)
            DB-->>Route: "{ data: existingApp }"
            Route-->>Client: 400 Already applied
        else not yet applied (null)
            DB-->>Route: "{ data: null, error: null }"
            Route->>DB: INSERT application .select().single()
            DB-->>Route: "{ data: application }"
            Route->>Route: Reputation, email, activity, webhook
            Route-->>Client: "201 { application }"
        end
    end
Loading

Comments Outside Diff (2)

  1. src/app/api/applications/route.ts, line 120-124 (link)

    P2 The applicantProfile query uses .single() just like the two queries this PR fixed. If a user exists in auth but has no corresponding row in profiles (e.g., profile creation failed), .single() returns { data: null, error: PGRST116 } while .maybeSingle() returns { data: null, error: null }. The fallback on line 126 handles the null gracefully, but keeping .single() is inconsistent with the rest of the fix and would silently swallow a real missing-profile case via the same mechanism the PR is correcting.

  2. src/app/api/applications/route.ts, line 45-49 (link)

    P2 Database errors silently masked as 404/400

    Neither .maybeSingle() call (lines 45 and 74) destructures error, so a real database failure (connection loss, RLS policy error, etc.) will set data to null while error carries the actual problem. The code will then respond with "Gig not found" (404) or proceed as if no duplicate application exists, hiding the true cause. Consider destructuring and short-circuiting on error to surface real failures distinctly from the expected 0-row case.

Reviews (1): Last reviewed commit: "fix: use .maybeSingle() in applications ..." | Re-trigger Greptile

@ralyodio ralyodio closed this Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants