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