The "EdgeFunctionError: Function invocation timeout" error occurs when a Supabase Edge Function exceeds its maximum execution time limit. This typically happens with long-running operations, infinite loops, or inefficient code that takes too long to complete within the function's time constraints.
The "EdgeFunctionError: Function invocation timeout" error (Error 546) indicates that a Supabase Edge Function has exceeded its maximum allowed execution time. Supabase Edge Functions run on Deno with strict resource limits to ensure fair usage and prevent runaway processes. Edge Functions have a default timeout limit (typically 10-30 seconds depending on your plan) to prevent functions from running indefinitely. When a function exceeds this time limit, the Deno runtime terminates it and returns this error to the client. This error is particularly common when: - Performing CPU-intensive computations - Making multiple sequential API calls without proper optimization - Processing large datasets without pagination or streaming - Having infinite loops or recursive functions without proper exit conditions - Waiting for external services that are slow or unresponsive The timeout protects both your application and Supabase's infrastructure from resource exhaustion, but requires developers to write efficient, well-optimized functions that complete within the allotted time.
Break down CPU-intensive work and use parallel execution where possible:
// Instead of sequential API calls
const results = [];
for (const item of items) {
const result = await fetchExternalApi(item); // Slow!
results.push(result);
}
// Use Promise.all for parallel execution
const promises = items.map(item => fetchExternalApi(item));
const results = await Promise.all(promises); // Much faster!For CPU-bound tasks, consider:
1. Chunk processing: Break large datasets into smaller batches
2. Stream processing: Use streams for file uploads/downloads
3. Web Workers: Offload heavy computation (if supported)
4. External services: Use dedicated compute services for heavy processing
Add explicit timeouts to prevent waiting indefinitely for slow external services:
// Set timeout for fetch requests
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
try {
const response = await fetch('https://api.example.com/data', {
signal: controller.signal
});
clearTimeout(timeoutId);
// Process response
} catch (error) {
if (error.name === 'AbortError') {
console.error('Request timed out');
// Return cached data or fallback response
}
throw error;
}For database queries:
// Supabase client with statement timeout
const { data, error } = await supabase
.from('users')
.select('*')
.limit(1000)
.timeout(3000); // 3 second timeoutAvoid loading entire datasets into memory. Use pagination or streaming instead:
// Pagination example
async function processAllUsers() {
let page = 0;
const pageSize = 100;
let hasMore = true;
while (hasMore) {
const { data: users, error } = await supabase
.from('users')
.select('*')
.range(page * pageSize, (page + 1) * pageSize - 1);
if (error) throw error;
// Process this batch
await processUserBatch(users);
hasMore = users.length === pageSize;
page++;
}
}
// Streaming example for file processing
import { readableStreamFromReader } from "https://deno.land/[email protected]/streams/mod.ts";
async function processLargeFile(filePath: string) {
const file = await Deno.open(filePath);
const stream = readableStreamFromReader(file);
for await (const chunk of stream) {
// Process chunk by chunk
await processChunk(chunk);
}
file.close();
}Use Supabase Dashboard and logging to identify performance bottlenecks:
1. Check Edge Function logs in Supabase Dashboard:
- Go to Edge Functions → Select your function → Logs
- Look for execution time metrics
- Identify slow operations
2. Add performance logging:
console.time('database-query');
const { data, error } = await supabase.from('users').select('*');
console.timeEnd('database-query'); // Logs execution time
console.time('external-api');
const response = await fetch('https://api.example.com');
console.timeEnd('external-api');3. Use the Performance API:
const start = performance.now();
// Your code here
const duration = performance.now() - start;
console.log(`Operation took ${duration}ms`);4. Set up alerts for functions approaching timeout limits
For tasks that genuinely need more time, consider alternative architectures:
1. Background jobs with webhooks:
- Return immediately with a job ID
- Process in background
- Notify via webhook when complete
// Immediate response
export async function handler(req: Request) {
const jobId = generateJobId();
// Start background processing (e.g., queue to Redis)
await queueBackgroundJob(jobId, req);
return new Response(JSON.stringify({ jobId, status: 'processing' }), {
status: 202, // Accepted
headers: { 'Content-Type': 'application/json' }
});
}2. Chunk processing with checkpointing:
- Process data in chunks
- Save progress to database
- Resume from last checkpoint if interrupted
3. External compute services:
- Use AWS Lambda, Google Cloud Functions, or Azure Functions
- Call from Edge Function via HTTP
- Handle results asynchronously
4. Database functions:
- Move complex logic to PostgreSQL stored procedures
- Execute directly in database
- Return results to Edge Function
Test your Edge Functions with production-like data before deployment:
1. Load testing:
# Use tools like k6 or artillery for load testing
k6 run --vus 10 --duration 30s script.js2. Performance testing:
- Test with maximum expected data size
- Simulate slow network conditions
- Test concurrent requests
3. Monitoring in staging:
- Deploy to staging environment first
- Monitor execution times
- Set up alerts for performance degradation
4. Implement circuit breakers:
class CircuitBreaker {
private failures = 0;
private lastFailure = 0;
private readonly threshold = 5;
private readonly resetTimeout = 60000; // 1 minute
async execute(fn: () => Promise<any>) {
if (this.isOpen()) {
throw new Error('Circuit breaker open');
}
try {
const result = await fn();
this.reset();
return result;
} catch (error) {
this.recordFailure();
throw error;
}
}
private isOpen() {
return this.failures >= this.threshold &&
Date.now() - this.lastFailure < this.resetTimeout;
}
private recordFailure() {
this.failures++;
this.lastFailure = Date.now();
}
private reset() {
this.failures = 0;
}
}## Timeout Limits by Plan
Supabase Edge Functions have different timeout limits depending on your plan:
- Free Tier: 10 seconds execution time
- Pro Tier: 30 seconds execution time
- Enterprise: Custom limits (contact support)
## Deno Runtime Considerations
Edge Functions run on Deno, which has some important characteristics:
1. Single-threaded event loop: Like Node.js, Deno uses a single-threaded event loop. Blocking operations stall all other requests.
2. Memory limits: Functions also have memory limits (typically 128MB-1GB depending on plan). Memory exhaustion can cause termination.
3. Cold starts: Functions may experience cold starts if not invoked frequently, adding to execution time.
4. Global fetch: Deno has built-in fetch API, but network calls still count toward execution time.
## Best Practices
1. Keep functions stateless: Don't rely on in-memory state between invocations.
2. Use connection pooling: For database connections, use connection pools and reuse connections.
3. Implement retry logic: For transient failures, implement exponential backoff retry logic.
4. Cache responses: Cache expensive computations or external API responses when appropriate.
5. Use CDN for static assets: Serve large files from CDN, not through Edge Functions.
## Error Handling
Always implement proper error handling to provide meaningful feedback:
export async function handler(req: Request) {
try {
// Your function logic
const result = await processRequest(req);
return new Response(JSON.stringify(result), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
console.error('Function error:', error);
if (error.message.includes('timeout')) {
return new Response(JSON.stringify({
error: 'Request timeout',
suggestion: 'Try with smaller dataset or implement pagination'
}), {
status: 504,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response(JSON.stringify({ error: 'Internal server error' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}email_conflict_identity_not_deletable: Cannot delete identity because of email conflict
How to fix "Cannot delete identity because of email conflict" in Supabase
mfa_challenge_expired: MFA challenge has expired
How to fix "mfa_challenge_expired: MFA challenge has expired" in Supabase
conflict: Database conflict, usually related to concurrent requests
How to fix "database conflict usually related to concurrent requests" in Supabase
phone_exists: Phone number already exists
How to fix "phone_exists" in Supabase
StorageApiError: resource_already_exists
StorageApiError: Resource already exists