Context
-
Site:
punterx-core-staging
-
Base URL:
https://punterx-core-staging.netlify.app
-
Unique deploy tested:
https://68d3be1e3d8cd8b58182890f--punterx-core-staging.netlify.app
Functions involved
-
cron-match
(scheduled every 15 minutes) -
diag-rt
(unscheduled) — serves 200 JSON as health check
netlify.toml (relevant)
[functions]
directory = "netlify/functions"
included_files = ["netlify/functions/_lib/**"]
[functions."cron-match"]
schedule = "*/15 * * * *"
Handler (minimal top part of netlify/functions/cron-match.cjs
)
'use strict';
try { console.log("[cron-match] TOP: module load", new Date().toISOString()); } catch(_) {}
exports.handler = async (event, context) => {
try {
const qs = (event && event.queryStringParameters) || {};
if (qs && qs.noop === "1") {
try { console.log("[cron-match] NOOP"); } catch(_){}
return { statusCode: 200, headers: { 'content-type': 'application/json' },
body: JSON.stringify({ ok:true, mode:"noop", scheduled: !!(event&&event.headers&&event.headers['x-nf-scheduled']), tag:"[SAFE_SHIM]" }) };
}
} catch (_){}
const scheduled = !!(event && event.headers && event.headers['x-nf-scheduled']);
try { console.log("[cron-match] enter", { scheduled }); } catch(_){}
return { statusCode: 200, headers: { 'content-type': 'application/json' },
body: JSON.stringify({ ok:true, scheduled, tag:"[SAFE_SHIM]" }) };
};
What happens
-
GET {unique-deploy}/.netlify/functions/diag-rt
→ 200 JSON -
GET {unique-deploy}/.netlify/functions/cron-match?noop=1
→ 500 text/plain-
Response shows only
Internal Error. ID: <x-nf-request-id>
-
No entries appear in Function Logs for those request IDs (suggests the error is pre-handler).
-
-
A temporary unscheduled alias (
cron-health
) responding with the same SAFE_SHIM returned 200 JSON when unscheduled; when scheduled, it behaved likecron-match
(500 + no logs).
Recent request IDs (failing 500s)
-
01K5XJ414X00D3WJW8HGAP58QZ
-
01K5XJ5C23NHQHK93ZDFXJFMVA
(others available if helpful)
Diagnostics
-
diag-rt
returns OK with Node seen as20.19.4
/22.18.0
depending on instance. -
A diagnostic function (
diag-cron-bundle
) reports:
{
"notes": ["Listed functions dir and hashed cron entry (auto)"],
"cron": { "missing": true },
"here": "/var/task"
}
What I’ve tried
-
Ensured only one entry file exists for this function; removed backups and prebuilt ZIPs/manifest from the repo.
-
Tried both
cron-match.cjs
andcron-match-log.cjs
names; also tested.js
vs.cjs
. -
Renamed function (
cron-match-log
→cron-match
) and updatednetlify.toml
. -
Deployed with
--skip-functions-cache
multiple times; local builds cleaned. -
Verified other functions (including
core-runner
anddiag-rt
) serve 200 in the same deploy. -
Confirmed scheduled behavior and aware that scheduled functions aren’t URL invokable in production per docs; issue here is that even a NOOP query to the same handler (when scheduled) returns 500 before the handler runs (no Function Logs), whereas the unscheduled alias hits the handler and returns 200.
What I need help with
-
Is the 500 pre-handler with no Function Logs the expected behavior for a scheduled function when hit via URL in production, or should it be a 404/clearer response?
-
If 500 is expected, is there a recommended pattern to expose a safe debug/health path for the same code without scheduling conflicts (beyond maintaining a separate unscheduled alias)?
-
Anything obvious in my setup that would cause the runtime to treat the scheduled function’s URL route differently from others (given
diag-rt
andcore-runner
work fine)?
Environment
-
Netlify CLI:
23.6.0
-
OS: GitHub Codespaces (Linux)
-
Node (observed in responses):
20.19.4
/22.18.0
Thanks!