Skip to main content

CORS OPTIONS Preflight Fix - Deployment Summary

Date: 2026-01-18
Issue: OPTIONS preflight requests returning 404 on payroll-backend-prod for hierarchy endpoints
Commit: 7cd7f2848f6077e3abcf4ca7a5c4f451a94d2144

Problem

CORS preflight (OPTIONS) requests were failing with 404:
  • OPTIONS /api/v1/admin/agents/resolver → 404
  • OPTIONS /api/v1/admin/hierarchy/* → 404
This blocked frontend from making GET/POST requests, breaking:
  • Agent Mapping resolver cache
  • Export Agent IDs (CSV)
  • Hierarchy tools

Root Cause

FastAPI’s CORSMiddleware should handle OPTIONS automatically, but it wasn’t working for routes with complex dependencies (like require_admin_or_ceo). The middleware might not handle OPTIONS for routes that don’t exist or routes that fail dependency checks before CORS can respond.

Solution

Added explicit OPTIONS handlers for all hierarchy endpoints:
  1. /api/v1/admin/agents/resolveroptions_agent_resolver()
  2. /api/v1/admin/hierarchy/reparentoptions_hierarchy_reparent()
  3. /api/v1/admin/hierarchy/batch_reparentoptions_hierarchy_batch_reparent()
  4. /api/v1/admin/hierarchy/bootstrapoptions_hierarchy_bootstrap()
  5. /api/v1/admin/hierarchy/treeoptions_hierarchy_tree()
  6. /api/v1/admin/hierarchy/historyoptions_hierarchy_history()
Each handler:
  • Returns 204 No Content (standard for OPTIONS)
  • CORSMiddleware automatically adds CORS headers
  • No auth dependencies (OPTIONS requests don’t include auth headers)

Code Changes

File: api/routes/admin_hierarchy.py Added OPTIONS handlers (6 total):
@router.options("/admin/agents/resolver")
async def options_agent_resolver():
    """OPTIONS handler for CORS preflight - CORSMiddleware adds headers."""
    from fastapi.responses import Response
    return Response(status_code=204)
Minimal diff: 46 lines added (6 OPTIONS handlers + imports)

Deployment Status

Commit: 7cd7f2848f6077e3abcf4ca7a5c4f451a94d2144
Status: ⚠️ Deployment failed (container startup timeout)
Current Revision: payroll-backend-prod-00161-g9n (previous revision, still serving traffic) Deployment Error: Container failed to start and listen on port 8080 within timeout. This appears to be unrelated to the OPTIONS handler changes (code compiles, syntax is correct).

Next Steps

  1. Investigate deployment failure:
    • Check Cloud Run logs for startup errors
    • Verify Dockerfile and startup command
    • Check if there are any import errors or missing dependencies
  2. Retry deployment after fixing startup issue:
    gcloud run deploy payroll-backend-prod --source . \
      --region us-central1 \
      --project payroll-bi-gauntlet \
      --service-account 238826317621-compute@developer.gserviceaccount.com \
      --set-env-vars GCP_PROJECT_ID=payroll-bi-gauntlet,GIT_COMMIT_SHA=7cd7f2848f6077e3abcf4ca7a5c4f451a94d2144 \
      --memory 1Gi --cpu 1 --timeout 300 \
      --concurrency 80 --max-instances 10 --min-instances 0 \
      --allow-unauthenticated --clear-base-image
    
  3. Post-deploy verification:
    # Test OPTIONS preflight
    curl -i -X OPTIONS \
      "https://payroll-backend-prod-238826317621.us-central1.run.app/api/v1/admin/agents/resolver?include_inactive=true" \
      -H "Origin: https://payroll-pipeline-cbs.vercel.app" \
      -H "Access-Control-Request-Method: GET" \
      -H "Access-Control-Request-Headers: authorization,x-org-id"
    
    # Expected: 204 No Content with CORS headers
    # - Access-Control-Allow-Origin: https://payroll-pipeline-cbs.vercel.app
    # - Access-Control-Allow-Methods: GET, OPTIONS, ...
    # - Access-Control-Allow-Headers: authorization, x-org-id, ...
    

Verification Checklist

After successful deployment:
  • OPTIONS /api/v1/admin/agents/resolver returns 204 (not 404)
  • CORS headers present: Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers
  • Browser DevTools: No CORS errors when calling resolver endpoint
  • Export Agent IDs (CSV) works in browser
  • Hierarchy tools load without resolver errors

Notes

  • OPTIONS handlers are minimal and safe - they don’t change business logic
  • CORSMiddleware configuration remains unchanged (already correct)
  • This fix is compatible with existing CORS setup
  • No RBAC/auth changes - OPTIONS handlers have no dependencies