Fix: Vercel Deployment Protection Blocking Internal API Calls
Date: October 18, 2025
Status: โ FIXED
Branch:mainCommit:a0cc8120
๐ด Problem Summary
After fixing the server-side URL construction issue, scheduled backups were still failing with a 401 Authentication Required error. The error showed an HTML authentication page from Vercel instead of the expected JSON response.
Cron Endpoint โ executeBackupJob() โ executeBatchCopyOperations()
(direct function call) (direct function call)
Implementation Details
1. Created Shared Backup Execution Logic
File:src/lib/backup/execute-backup-job.ts
exportasyncfunctionexecuteBackupJob( jobId:string, userId:string,):Promise<ExecuteBackupJobResult>{// All backup execution logic moved here// Can be called directly without HTTP requests}
Benefits:
No HTTP requests = No deployment protection issues.
Reusable logic for both cron and manual execution.
const result =awaitexecuteBackupJob(job.id, job.userId);
3. Updated Execute API Route
File:src/app/api/jobs/[id]/execute/route.ts
The API route is now a thin wrapper around executeBackupJob():
exportasyncfunctionPOST(req:NextRequest,{ params }){const{ id: jobId }=await params;// Get userId from auth or jobconst userId =awaitgetUserId(req, jobId);// Execute using shared logicconst result =awaitexecuteBackupJob(jobId, userId);returncreateSuccessResponse(result);}
4. Enhanced Copy Service
File:src/lib/rclone/services/copy-service.ts
Added optional userId parameter to support server-side token retrieval:
exportasyncfunctionexecuteBatchCopyOperations( operations:CopyOperationRequest[], userId?:string,// For server-side token retrieval):Promise<...>{// Pass userId to each operation for database token access}
๐ Technical Benefits
1. No More HTTP Overhead
Direct function calls are faster than HTTP requests.
No serialization/deserialization of JSON.
No network latency (even for localhost).
2. Better Error Handling
Errors are thrown directly, not wrapped in HTTP responses.
Stack traces are preserved.
Easier to debug.
3. Simpler Code
No need to construct URLs.
No need to handle HTTP status codes.
No need to parse response bodies.
4. More Testable
Can test business logic without mocking HTTP.
Can test with different user contexts easily.
Can test error scenarios more easily.
5. Deployment Protection Proof
Works regardless of Vercel deployment protection settings.
Works in all environments (Development, Preview, Production).
No authentication bypass tokens needed.
๐งช Testing & Verification
Before Deploying
Type Check:
pnpm typecheck
Result: โ No errors
Lint Check:
pnpm lint
Result: โ No errors
After Deploying to Production
Wait for next cron execution (within 5 minutes)
Check backup job status:
node scripts/investigate-failed-backup.mjs
Should show no new failures
Verify in database:
Jobs should be marked as "completed" instead of "failed".
No "401" errors in lastError field.
Check destination folders:
Navigate to backup destination in Google Drive/OneDrive.
โ Created BACKUP_EMPTY_DIRECTORIES_FIX.md - Documentation for previous fix.
Next Steps:
Deploy to production with vercel --prod or merge to main branch
Monitor first cron execution (within 5 minutes)
Verify backup files are copied successfully
Confirm no more 401 authentication errors
Close related issues/tickets
๐ฏ Summary
The issue was caused by Vercel Deployment Protection blocking internal HTTP requests between API endpoints. The solution was to refactor the code to use direct function calls instead of HTTP fetch() calls. This is a better architecture anyway, as it's faster, more testable, and more maintainable.
Key Takeaway: When building server-side applications, prefer direct function calls over HTTP requests for internal communication. HTTP should be reserved for external services or client-server communication.