Senior Application Developer

loc: Maynooth, ON K0L 2S0tel: 613-553-0960email: rgsamways@gmail.com
Robin Samways

Farpost Pulse · Infrastructure

$ Azure said the deploy succeeded. The app had zero functions.

`func azure functionapp publish` reported complete success — every step "completed," and Azure's own Deployment Center independently confirmed "Succeeded (Active)." And yet every HTTP endpoint 404'd, and the Function App's dashboard showed zero registered functions, the same screen shown for a brand-new, never-deployed app. Nothing about the deploy command's own output, or the platform's own status, pointed at why.

Working through the obvious candidates first — a routing misconfiguration, a restart, a deeper look at the deployment logs — ruled each one out without finding the actual cause. The real breakthrough came from the live Log stream, watched while triggering a fresh request: the runtime's own startup log showed it actively searching for functions and finding none. Not crashing, not erroring — just quietly finding nothing, which is exactly why none of the deployment-layer checks had surfaced anything.

The fix

The root cause, once found, was two things compounding: the deploy had used a local build rather than Azure's own server-side build step, and `.funcignore` excluded `node_modules` from the uploaded package. Locally-built code with its dependencies stripped out means every function file's top-level `require()` call silently fails, which quietly prevents that file from ever registering itself. The fix — removing `node_modules` from `.funcignore` — was confirmed working two ways before even checking the app again: the deploy package jumped from 11.2 KB to 8.2 MB, and the Log stream then showed all four functions actually registering.

Why this matters

A platform reporting "deployment succeeded" only confirms the upload/build pipeline finished — it says nothing about whether the runtime can actually load and register anything from what got uploaded. Those are two genuinely separate layers of "success," and only one of them is visible by default. The generalizable habit: after a "successful" deploy, check the runtime's own live behavior directly — a real log stream, a real request — rather than trusting the deployment platform's own success report as the final word.

Feedback on this page