Skip to main content

Common Issues

Known issues, gotchas, and their fixes. These are problems the team has encountered before -- check here first when something breaks.

Database Column Name Mismatches

seniority vs seniority_level

Problem: Code references seniority_level but the column does not exist.

Fix: The attorneys table uses seniority (not seniority_level). Update any queries or code to use the correct column name.

-- Correct
SELECT seniority FROM attorneys WHERE id = '...';

-- Wrong -- will throw "column does not exist"
SELECT seniority_level FROM attorneys WHERE id = '...';

email_status Enum Values

Problem: Inserting a row with email_status = 'unverified' fails with an enum validation error.

Fix: The email_status column only accepts these four values:

Allowed Values
valid
invalid
catch_all
unknown

There is no unverified value. Use unknown instead if the status has not been determined.

disposition is TEXT, Not Enum

Problem: Code tries to cast or validate disposition against an enum type that no longer exists.

Fix: The calls.disposition column was migrated from the call_disposition enum to plain TEXT in migration 20260210200001_convert_disposition_to_text.sql. It now accepts any string, but should always be set to one of the 9 canonical dispositions in Title Case:

  1. No Answer
  2. Voicemail
  3. Gatekeeper
  4. Incorrect Number
  5. Not Interested
  6. Callback Requested
  7. Future Potential
  8. Meeting Booked
  9. Do Not Contact

Type System Issues

attorneys Table Not in Auto-Generated Types

Problem: TypeScript types for the attorneys table are missing or stale after regenerating Supabase types.

Cause: The attorneys table was created via the Supabase dashboard, NOT through migration files. The Supabase type generator only picks up tables defined in migrations.

Fix: Types for the attorneys table are manually maintained in src/integrations/supabase/types.ts. After regenerating types, you must manually re-add the attorneys table definition. The full interface is also defined in src/lib/attorney-utils.ts.

Sales Types Not in Supabase Types

Problem: TypeScript types for sales_prospects, sales_calls, or sales_meetings are not found in Supabase types.

Fix: Sales-specific types are defined in src/lib/sales-types.ts, not in the Supabase types file. Import from the correct location:

// Correct
import type { SalesProspect, SalesCall } from '@/lib/sales-types';

// Wrong -- may not exist in Supabase types
import type { Database } from '@/integrations/supabase/types';

Blitz API Issues

422 Errors from Email/Phone Endpoints

Problem: Blitz API returns HTTP 422 (Unprocessable Entity) when calling email or phone enrichment.

Cause: Using the wrong field name. The v2 API requires person_linkedin_url, but older code may use linkedin_profile_url.

Fix:

// Correct (v2)
const payload = { person_linkedin_url: 'https://linkedin.com/in/...' };

// Wrong -- causes 422
const payload = { linkedin_profile_url: 'https://linkedin.com/in/...' };

GHL Issues

Mixed Case callStatus

Problem: GHL callStatus comparisons fail because values are mixed case.

Cause: GHL sends callStatus in inconsistent casing: Answered, No answer, completed, Busy, etc.

Fix: Always normalize to lowercase before comparing:

const status = payload.callStatus?.toLowerCase();
if (status === 'answered' || status === 'completed') {
// Someone picked up
}

Duplicate Call Records

Problem: The same call appears twice in the database.

Cause: GHL fires 2 webhook hits per call (Call Completed + Disposition workflows).

Fix: Always dedup on external_call_id before inserting:

SELECT id FROM sales_calls WHERE external_call_id = $1 LIMIT 1;

If a record exists, skip the insert and return 200 to acknowledge the webhook.

Calendar Issues

Wrong Calendar Table

Problem: Calendar connection queries return empty results even though the user has connected their calendar.

Cause: Client mode and internal mode use different tables.

Fix:

ModeTable
Client bookingscalendar_connections
Internal (user) bookingsuser_calendar_connections

Check which mode the booking link uses:

const isInternalLink = !bookingLink?.client_id && !!bookingLink?.user_id;

Then query the correct table.

OAuth State Parsing

Problem: OAuth callback fails or redirects to the wrong page.

Cause: The state parameter format differs between client and internal modes.

ModeState FormatRedirect After OAuth
Client{clientId}:{provider}/workspace/{clientId}/client-info
Internaluser:{userId}:{provider}/admin/sales/scheduling

Ensure the callback handler correctly parses both formats.

Build and Deployment Issues

Vite Build Fails with Type Errors

Problem: npm run build fails with TypeScript errors that do not appear in the dev server.

Cause: Vite's dev server is more lenient than the production build. The build runs tsc in strict mode.

Fix: Run npm run lint and fix all TypeScript errors before building.

Edge Function Returns 401

Problem: An edge function returns 401 Unauthorized even with a valid request.

Cause: JWT verification is enabled by default. Webhook endpoints from external services cannot send JWTs.

Fix: Set verify_jwt = false in supabase/config.toml for the affected function, then redeploy:

[functions.ghl-call-webhook]
verify_jwt = false
supabase functions deploy ghl-call-webhook