Netlify Scheduled Functions Debugging Guide 2026
Debug Netlify scheduled functions with real error patterns, production code, and console solutions for indie hackers.
TL;DR
Netlify scheduled functions (via Functions with cron triggers) fail silently by default. Enable structured logging, use console.log() strategically, check function logs in the Netlify UI or via CLI, and validate cron expressions before deployment. Common errors: timezone mismatches, missing environment variables, and handler timeouts.
---
The Silent Killer: Scheduled Functions That Never Run
Scheduled functions are deceptively simple until they're not. Unlike HTTP-triggered functions that return errors visibly, scheduled functions can silently fail—your cron job never executes, and you won't know until your data isn't synced or emails aren't sent.
I've seen this pattern dozens of times: a developer deploys a scheduled function, it appears "successful," but the actual job never runs. The cron syntax was wrong. The handler crashed. The environment variables weren't loaded. Without proper debugging setup, you're flying blind.
This guide covers the exact debugging patterns we use at StillNotAThing for scheduled functions handling daily reports, database maintenance, and webhook retries.
---
Understanding Netlify Scheduled Functions (Verify in official docs)
Netlify Functions support scheduled execution via schedule property in the function config. As of early 2026, this feature uses cron expressions and runs on a best-effort basis (not guaranteed SLA). [Verify exact SLA in official Netlify Functions docs](https://docs.netlify.com/functions/overview/).
Scheduled functions are defined in netlify/functions/ with a config file:
```javascript // netlify/functions/daily-report.js exports.handler = async (event) => { console.log('Scheduled function triggered at:', new Date().toISOString()); // Your logic here return { statusCode: 200, body: 'Success' }; }; ```
With accompanying config:
```toml
netlify/functions/daily-report.toml
schedule = "0 9 * * *" # 9 AM UTC daily ```---
Production-Ready Debugging Pattern
Here's the pattern that catches real issues:
```javascript // netlify/functions/sync-data.js const fetch = require('node-fetch');
function logEvent(level, message, context = {}) { const timestamp = new Date().toISOString(); const logEntry = { timestamp, level, message, context, functionName: 'sync-data', }; console.log(JSON.stringify(logEntry)); }
exports.handler = async (event) => { logEvent('INFO', 'Function execution started', { eventSource: event.source, // 'schedule' for cron });
try { // Verify environment variables exist if (!process.env.API_KEY) { logEvent('ERROR', 'Missing API_KEY environment variable'); return { statusCode: 500, body: JSON.stringify({ error: 'Configuration error' }), }; }
logEvent('DEBUG', 'Fetching data from upstream API', { endpoint: process.env.API_ENDPOINT, });
const response = await fetch(${process.env.API_ENDPOINT}/data, {
headers: { Authorization: Bearer ${process.env.API_KEY} },
timeout: 25000, // Netlify timeout is 26s for free tier
});
if (!response.ok) { logEvent('ERROR', 'API returned error status', { status: response.status, statusText: response.statusText, }); return { statusCode: 502, body: JSON.stringify({ error: 'Upstream API error' }), }; }
const data = await response.json(); logEvent('INFO', 'Data fetched successfully', { recordCount: data.length, });
// Process data const processed = data.map(item => ({ ...item, processedAt: new Date().toISOString(), }));
logEvent('INFO', 'Function completed successfully', { recordsProcessed: processed.length, });
return { statusCode: 200, body: JSON.stringify({ processed: processed.length }), }; } catch (error) { logEvent('ERROR', 'Unhandled exception', { errorMessage: error.message, errorStack: error.stack.split('\n').slice(0, 3), // First 3 stack frames });
return { statusCode: 500, body: JSON.stringify({ error: 'Internal server error' }), }; } }; ```
---
Real Error Messages You'll See
Error 1: Cron Expression Validation
``` ERROR: Invalid cron expression in daily-report.toml Expected: "0 9 * * *" (minute hour day month weekday) Got: "9 * * *" Context: Missing minute field ```Fix: Use [cron.guru](https://cron.guru) to validate syntax. Format is strict: minute hour day month weekday.
Error 2: Handler Timeout
``` ERROR: Function execution timed out after 26000ms Function: sync-data Context: Request to external API exceeded timeout window Suggestion: Set explicit fetch timeout lower than 26s ```Fix: Always set timeouts explicitly: ```javascript const response = await fetch(url, { timeout: 20000 }); // 20s, not 26s ```
Error 3: Missing Environment Variables at Runtime
``` ERROR: process.env.DATABASE_URL is undefined Function: daily-report Context: Attempted to connect to database Location: netlify/functions/daily-report.js:42 ```Fix: Verify variables in Netlify UI (Site Settings → Environment) and use fallbacks: ```javascript const dbUrl = process.env.DATABASE_URL || 'http://localhost:5432'; ```
---
Accessing Logs
Option 1: Netlify UI
1. Go to Site → Functions → [function-name] 2. View "Invocations" tab 3. Click specific execution to see full logsOption 2: Netlify CLI (verify current version in official docs)
```bash netlify functions:invoke daily-report --identity ```Option 3: Real-time Streaming
```bash netlify dev --functions=netlify/functions ``` Scheduled functions will execute on the defined cron schedule during local dev.---
Common Debugging Checklist
schedule property exists in .toml config file.env file{ statusCode: 200 } on successnetlify dev reproduces behavior---
See Also
---
What am I missing?
Has your team encountered different failure modes with Netlify scheduled functions? Are there logging strategies that work better for your use case? Drop corrections and additions in the comments—this guide will improve with your feedback.