Home › Cloud › App Service 502.5: Process Failure on Startup
Beginner 6 min · September 23, 2026

App Service 502.5: Process Failure on Startup

Fix App Service 502.5 by reading startup logs first: enable App Service logs, check stdout output, and align the runtime version..

N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Drawn from code that ran under real load.

Follow
✓ Production
production tested
September 26, 2026
last updated
2,085
articles · all by Naren
Before you start⏱ 11 min
  • ✓An Azure App Service you can restart and configure
  • ✓Azure CLI installed with az login completed
  • ✓Basic familiarity with deploying a web app
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • HTTP 502.5 means your app crashed before answering a single request: the platform is fine, your process died on startup
  • Turn on App Service logs, restart once, and watch Log Stream: stdout usually names the exact crash within seconds
  • The top cause is a runtime mismatch: your app targets .NET 8 while the App Service still runs .NET 6
  • Check app settings too: a missing connection string throws at startup and looks just like a code bug
✦ Definition~90s read
What is Azure App Service 502.5 Process Failure?

HTTP Error 502.5 on Azure App Service means the web front end couldn't get a response from your application process because that process failed. On Windows workers, ANCM (the ASP.NET Core Module in IIS) launches your dotnet process and proxies requests to it; if the process exits during startup, ANCM reports a process failure.

★
Think of App Service as a restaurant kitchen and your app as the recipe on the wall.

On Linux workers, the container runs your startup command, and if that command crashes, the front end has nothing to forward to. The number 502.5 distinguishes this from other bad-gateway flavors: .3 means the backend closed the connection, .5 means the backend process itself failed.

Three failure modes dominate. First, runtime mismatch: a framework-dependent app asks for a runtime version the worker doesn't have, and the host kills the process before your code runs. Second, startup exceptions: your Program.cs or Startup class throws — missing config, unreachable database, bad DI registration — and the unhandled exception tears the process down.

Third, launch misconfiguration: a corrupt web.config processPath on Windows or a wrong startup command on Linux means the platform can't even start your code.

Evidence comes from four log sources. Application Logging captures your stdout and stderr. Detailed Error Messages render the failing module and handler. Failed Request Tracing records the IIS pipeline step that raised. Docker logs on Linux show container startup.

All four live under /LogFiles via Kudu and stream through Log Stream once enabled. They are off by default, which is why the error page looks so unhelpful.

The mental model is simple: the platform is a healthy hallway, your process is a room at the end of it. A 502.5 means the room is dark. Stop inspecting the hallway and go look in the room — its logs name the reason it went dark.

Plain-English First

Think of App Service as a restaurant kitchen and your app as the recipe on the wall. Error 502.5 means the kitchen is open but the cook quit before making a single dish. The fix is never to rebuild the kitchen — it's to learn why the cook quit: a missing ingredient (app setting), a wrong oven (runtime mismatch), or a bad first step (startup crash). The kitchen notebook (stdout logs) holds the reason.

You deploy on a quiet Thursday afternoon, open the site to verify, and meet a bare error page: HTTP Error 502.5, process failure. No stack trace, no friendly message, just a number. Your first instinct says Azure is broken. Your second instinct says roll back. Both instincts skip the step that actually ends the outage: reading the one log line that names the crash.

Error 502.5 is App Service telling you the platform did its job and your app died anyway. The front end accepted the request, tried to hand it to your process, and found nothing alive on the other side. The cause is almost always local to your deployment: a runtime the host doesn't have, an exception in startup code, or a setting that exists on your laptop and nowhere else.

Beginners lose the most time here because the error page offers no clues while the clues sit one click away in Log Stream. Veterans lose time too, by redeploying on theories instead of reproducing with logging switched on.

This guide shows the exact order that ends 502.5 fast: enable App Service logs, restart once, read stdout, and fix what it names. You'll learn the runtime mismatch pattern behind most cases, see a real Friday-deploy incident, and leave with a pipeline that refuses to ship a worker that can't start.

What HTTP 502.5 Means on App Service (and What It Doesn't)

HTTP Error 502.5 on App Service has one specific meaning: the front end received your request but the worker process that should answer it failed. On Windows this surfaces through ANCM, the IIS module that launches your dotnet process and proxies traffic to it. On Linux it surfaces through the container's startup command and the language worker. Either way, the platform side is healthy — load balancer, networking, and the web server all work. What failed is your application starting up and staying alive.

This distinction decides your whole response. A platform problem calls for Azure status pages and support tickets. A 502.5 calls for your own logs, because the answer lives in your process's stdout output. Treating it as an outage wastes the first hour; treating it as a startup crash usually ends the incident in fifteen minutes. Check the App Service state first: if it says Running yet every request 502.5s, that's the classic signature — the host is up, the app is down.

The error page itself tells you almost nothing by design, since detailed errors are off by default in production. Don't stare at it. Move immediately to Log Stream with application logging enabled. Beginners often assume the lack of detail means the lack of evidence. The opposite is true: App Service captures stdout, Docker logs, detailed errors, and failed-request traces, but only if you switch them on. The rest of this guide walks that path in the order that wastes the least time.

📊 Production Insight
Teams that alert on the 502.x rate in App Service HTTP logs catch startup crashes while users are still retrying. One shop's alert fired two minutes after a bad deploy; the on-call engineer read stdout, saw the framework error, and fixed the stack before support received a single ticket.
🎯 Key Takeaway
502.5 is a dead app process behind a healthy front end — reach for your logs, not the Azure status page.

Reading Stdout Logs: Your Fastest Path to the Crash

Stdout is where dying .NET, Node, and Python apps confess, and App Service captures it once you ask. Application Logging (Filesystem) writes your console output to files under /LogFiles that you can tail live. Detailed Error Messages add the rich HTML error pages with the failing module and handler. Failed Request Tracing records the full IIS pipeline for requests that match your failure definitions. Together they turn a bare 502.5 into a named exception with a stack trace.

The workflow is deliberately boring: enable the three log sources, restart the app once, and tail the stream. The restart matters because startup crashes only emit their evidence during startup — tailing a long-dead process shows nothing. Watch the first thirty seconds after the restart line. The first exception in that window is almost always the cause; the errors after it are consequences of the process dying, not separate problems worth chasing.

For Windows apps, supplement Log Stream with the Kudu file browser at your-app.scm.azurewebsites.net, where eventlog.xml and the per-process stdout files persist across restarts. For Linux, the Docker logs in the same LogFiles directory show container startup, package restores, and the exact command that failed. The snippet below enables everything in one pass so you never debug blind again.

enable-app-logs.shBASH
1
2
3
4
5
6
7
8
9
10
# Enable every useful log source in one pass
az webapp log config --name <APP_NAME> --resource-group <RG> \
  --application-logging filesystem \
  --detailed-error-messages true \
  --failed-request-tracing true \
  --web-server-logging filesystem

# Restart once so the crash re-emits its evidence, then tail live
az webapp restart --name <APP_NAME> --resource-group <RG>
az webapp log tail --name <APP_NAME> --resource-group <RG>
📊 Production Insight
One team made log-enabling part of their deploy pipeline: every release turns on filesystem logging automatically. Their mean time to diagnose startup crashes dropped from forty minutes to under five, because nobody ever starts an incident with logging off anymore.
🎯 Key Takeaway
Enable logs, restart once, read the first exception in the thirty seconds after startup.

Runtime and Version Mismatches That Kill Startup

Most 502.5s come down to a version the host doesn't have. A framework-dependent .NET app needs the exact shared runtime installed on the worker: .NET 8 code on a .NET 6 worker dies instantly with a framework-not-found message. The same applies to Node and Python stacks — package.json asking for Node 20 on a Node 18 worker, or requirements needing a Python the image lacks. The deploy succeeds because deployment never runs your code; startup fails because startup always does.

Confirm both sides before changing anything. The platform side comes from az webapp config show, which reports linuxFxVersion or the Windows stack. The available side comes from az webapp list-runtimes, which lists every runtime your region actually offers — regions differ, so never assume. The app side comes from your project file's TargetFramework or engines field. When the major versions disagree, you've found the crash without reading another log line.

You have two durable fixes. The quick one sets the App Service stack to match the app. The stronger one publishes self-contained, bundling the runtime with your deployment so host versions stop mattering entirely. Self-contained costs some artifact size and gives up automatic runtime patching, but it deletes an entire class of midnight pages. Either way, add a pipeline assertion comparing TargetFramework to the stack — framework bumps should be impossible to ship without the hosting change.

check-app-runtime.shBASH
1
2
3
4
5
6
7
8
9
10
# What stack does this app actually run on?
az webapp config show --name <APP_NAME> --resource-group <RG> \
  --query "{linux:linuxFxVersion, windows:windowsFxVersion, net:netFrameworkVersion}" -o table

# What runtimes does this region even offer?
az webapp list-runtimes --os linux --query "[].{stack:runtime}" -o table

# Pin the stack to match the app (example: .NET 8 on Linux)
az webapp config set --name <APP_NAME> --resource-group <RG> \
  --linux-fx-version "DOTNETCORE|8.0"
📊 Production Insight
A platform rollout once removed an old runtime from workers and broke apps that had run untouched for a year. The survivors were all self-contained deployments. The lesson stuck: depending on a platform-installed runtime is depending on someone else's upgrade schedule.
🎯 Key Takeaway
Match the App Service stack to your TargetFramework, or publish self-contained and stop caring.

App Settings, Connection Strings, and Startup Throws

After runtimes, missing configuration is the biggest startup killer. Modern apps read connection strings, Key Vault URIs, and feature flags during startup, and a single absent key throws before the first request binds. It works on every laptop because local settings files and user secrets fill the gaps; it dies in Azure because the publish step deliberately excludes those files. The stdout log names the missing key plainly, which makes this a five-minute fix once you look.

Audit the effective settings rather than trusting memory. The portal's Configuration blade and the appsettings list command show exactly what the worker sees, including slot-specific overrides and Key Vault references. Diff that list against your local configuration on every incident — the missing entry usually jumps out immediately. Pay special attention after slot swaps, because a setting marked slot-specific stays with the slot while everything else moves, silently stranding the swapped app without its database string.

The structural fix has two halves. First, keep secrets out of files entirely: store them as app settings backed by Key Vault references so every environment resolves the same keys. Second, validate required settings at startup and crash loudly with the key name when one is absent. A startup error that says missing required setting: OrdersDbConnection beats a NullReference ten stack frames deep, both for your debugging and for the next person on call.

fix-app-settings.shBASH
1
2
3
4
5
6
7
8
9
10
# What settings does the worker actually see? Diff against local config
az webapp config appsettings list --name <APP_NAME> --resource-group <RG> -o table

# Add the missing key (production should use a Key Vault reference)
az webapp config appsettings set --name <APP_NAME> --resource-group <RG> \
  --settings OrdersDbConnection="@Microsoft.KeyVault(SecretUri=https://<VAULT>.vault.azure.net/secrets/OrdersDb/)"

# Restart once and confirm the startup throw is gone
az webapp restart --name <APP_NAME> --resource-group <RG>
az webapp log tail --name <APP_NAME> --resource-group <RG>
📊 Production Insight
Slot-specific settings cause the nastiest version of this bug: staging works with its own database string, the swap carries the code but not the string, and production crashes talking to nothing. One team now runs a settings-diff check before every swap and blocks promotion on any missing key.
🎯 Key Takeaway
Diff effective app settings against local config; validate required keys loudly at startup.

Diagnosing With Log Stream, Kudu, and Failed Request Tracing

When Log Stream is thin, go one layer deeper. Kudu — the .scm site next to every App Service — exposes the worker's filesystem, process explorer, and debug console through both a browser UI and a REST API. Under /LogFiles you'll find the Docker logs on Linux, detailed error HTML pages, failed-request traces, and on Windows the eventlog.xml plus per-process stdout files. These persist across restarts, so they hold evidence that live tailing missed.

Authenticate with the app's publishing credentials, which you can fetch from the CLI without resetting anything. Then curl the LogFiles virtual filesystem directly, or download the whole directory as a zip for offline grepping. The failed-request tracing XML files are verbose, but the winning move is simple: search for the first 502 status after your restart timestamp and read the module that raised it. If ANCM raised it before your code ran, suspect web.config or the startup command; if your code ran and threw, the exception details sit a few lines above.

Don't overlook the process explorer in Kudu either. If your process appears and vanishes in a loop, that's the platform restarting a crashing worker — consistent with a startup throw. If no process appears at all, the launch itself failed, which points at configuration rather than code. Either observation narrows the search before you read a single stack trace.

pull-kudu-logs.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
# Fetch publishing credentials without resetting them
az webapp deployment list-publishing-credentials \
  --name <APP_NAME> --resource-group <RG> \
  --query "{user:publishingUserName, pass:publishingPassword}" -o tsv > /tmp/kudu-creds.txt

# List the captured log files through Kudu
curl -u "$(cut -f1 /tmp/kudu-creds.txt):$(cut -f2 /tmp/kudu-creds.txt)" \
  "https://<APP_NAME>.scm.azurewebsites.net/api/vfs/LogFiles/"

# Download everything for offline grepping
az webapp log download --name <APP_NAME> --resource-group <RG> --log-file /tmp/app-logs.zip
unzip -o /tmp/app-logs.zip -d /tmp/app-logs && grep -rn "Exception\|error" /tmp/app-logs | head -30
📊 Production Insight
Intermittent 502.5s that survive restarts often turn out to be two workers disagreeing: one instance starts, another doesn't, and the load balancer alternates. Downloading logs per instance (the LogFiles directory splits by instance ID) reveals the split in minutes, while aggregate Log Stream hides it.
🎯 Key Takeaway
Kudu's LogFiles persist across restarts — pull them when live tailing shows too little.

Hardening Deploys So a Bad Startup Can't Take You Down

The final step is making a startup crash undeployable. Deployment slots exist precisely for this: deploy to staging, warm it with real requests, and swap only when the health endpoint answers. Auto-swap can do this hands-free, but only after you've proven the warmup path exercises true startup — a health check that returns 200 without touching the database proves nothing about the database string. Wire the warmup to the same readiness probe your orchestrator would use, hitting dependencies and failing loudly.

Keep the launch configuration in version control next to the code. On Windows that means web.config with the ANCM handler settings and process path; on Linux it means the explicit startup command in Configuration. Review changes to these files like code, because they are code — a one-line edit there carries the same blast radius as a migration. Diff them in the pipeline and block deploys when they change unexpectedly.

Close the loop with staged verification: deploy, call the health endpoint from the pipeline, run the smoke suite, then swap. If any step fails, the pipeline stops and staging holds the broken build where it can't hurt anyone. Rollback becomes a re-swap, measured in seconds. Teams that run this loop stop fearing deploys, because the pipeline has already survived every startup crash they're capable of shipping.

⚠ Prove Warmup Before You Automate Swaps
Never enable auto-swap before proving the warmup path. An auto-swap with a shallow health check promotes broken workers faster than any human could — you automate the outage instead of preventing it. Prove warmup catches a real startup crash first, then automate.
📊 Production Insight
One retailer runs this exact loop and hasn't had a startup crash reach production in eighteen months. Their staging slot catches roughly one bad build a quarter — usually a missing setting — and each catch takes ten minutes instead of becoming an incident.
🎯 Key Takeaway
Deploy to staging, warm with real checks, swap only on green — rollback is just a re-swap.
● Production incidentPOST-MORTEMseverity: high

The Framework Upgrade That Never Reached the Hosting Stack

Symptom
Every page on the site returned HTTP 502.5, including the health endpoint. The App Service showed as Running in the portal with normal CPU and memory. No application telemetry arrived because the process died before the telemetry SDK initialized.
Assumption
The team assumed Azure had broken something overnight, because nothing was deployed for a week. They opened a support ticket, restarted the app four times, and debated rolling back a week-old deploy. Each restart wiped the in-memory evidence while filesystem logging stayed off, so every attempt taught them nothing.
Root cause
The project had been retargeted to .NET 8 but the App Service stack remained on .NET 6, and the deployment was framework-dependent. The dotnet host couldn't find the .NET 8 runtime at startup, so the process exited before binding any port. The front end had nothing to talk to and returned 502.5 for every request.
Fix
The fix took two steps. First, they ran az webapp config show and saw the stack still pinned to .NET 6 while the project targeted .NET 8 — the latest deploy had silently carried the new target framework. They updated the stack to .NET 8 with az webapp config set, enabled filesystem logging, and restarted once. The site recovered immediately. The lasting fix was publishing self-contained for that service plus a pipeline check that fails the build when TargetFramework and the App Service stack disagree.
Key lesson
  • Turn logging on before you restart anything. Every blind restart destroys evidence; one logged restart usually names the crash and ends the incident.
  • Framework upgrades must include the hosting stack. A TargetFramework bump without the matching App Service stack is a guaranteed 502.5 waiting for the next deploy.
  • Alert on 502.x rate, not just on downtime. The error-rate spike pages you while the first users are still retrying, instead of after all of them have failed.
Production debug guideFive checks, in order, that take you from a bare 502.5 page to the named crash.5 entries
Symptom · 01
Logging is off and you're debugging blind
→
Fix
Run az webapp log config --name <APP> --resource-group <RG> --application-logging filesystem --detailed-error-messages true --failed-request-tracing true --web-server-logging filesystem. Then restart with az webapp restart --name <APP> --resource-group <RG> and watch az webapp log tail --name <APP> --resource-group <RG> — the crash line appears within seconds.
Symptom · 02
Stdout says the framework was not found
→
Fix
Run az webapp config show --name <APP> --resource-group <RG> --query "{linux:linuxFxVersion, windows:windowsFxVersion, net:netFrameworkVersion}" and compare against your project's TargetFramework. If they disagree on the major version, set the right stack with az webapp config set or republish self-contained.
Symptom · 03
Crash names a null setting or connection string
→
Fix
Dump the effective settings with az webapp config appsettings list --name <APP> --resource-group <RG> and diff them against your local configuration. Add the missing key with az webapp config appsettings set --settings KEY=value, then restart once and re-check Log Stream.
Symptom · 04
Log Stream shows nothing useful
→
Fix
Fetch publishing credentials via az webapp deployment list-publishing-credentials, then browse https://<APP>.scm.azurewebsites.net/api/vfs/LogFiles/ (stdout files, eventlog.xml) with curl. On Windows the ANCM startup errors land here even when Log Stream shows little.
Symptom · 05
The crash is intermittent across restarts
→
Fix
Run az webapp log download --name <APP> --resource-group <RG> --log-file /tmp/app-logs.zip, unzip, and grep the stdout and Docker logs for the first exception after the restart timestamp. The first error is the cause; everything after it is fallout.
App Service 502.5 Root Causes Compared
Root CauseHow to ConfirmFixPrevention
Runtime or SDK version mismatchStdout log says the framework was not found; az webapp config show lists a different stack than the app targetsSet the matching stack version or publish self-containedPin the runtime in config; assert it in the release pipeline
Exception thrown during startupLog Stream shows your exception type and stack trace seconds after restartFix the throwing code or missing dependencySmoke-test startup in staging with production-like settings
Missing app setting or connection stringNullReference or configuration error naming the key in stdout logsAdd the setting in Configuration or Key Vault referenceValidate required settings at startup; fail with the key name
Bad web.config or startup commandANCM reports process start failure with no app code executingRestore a known-good web.config or explicit startup commandVersion-control web.config and startup command; diff on deploy
⚙ Quick Reference
4 commands from this guide
FileCommand / CodePurpose
enable-app-logs.shaz webapp log config --name <APP_NAME> --resource-group <RG> \Reading Stdout Logs
check-app-runtime.shaz webapp config show --name <APP_NAME> --resource-group <RG> \Runtime and Version Mismatches That Kill Startup
fix-app-settings.shaz webapp config appsettings list --name <APP_NAME> --resource-group <RG> -o tab...App Settings, Connection Strings, and Startup Throws
pull-kudu-logs.shaz webapp deployment list-publishing-credentials \Diagnosing With Log Stream, Kudu, and Failed Request Tracing

Key takeaways

1
502.5 means your process died on startup
the platform is fine, so investigate the app, not Azure.
2
Enable App Service logs and read stdout first; the crash line usually names the exception in seconds.
3
Runtime mismatches cause most cases
align the App Service stack with your TargetFramework.
4
Missing app settings throw at startup
validate required keys loudly and back them with Key Vault.
5
Keep web.config and the Linux startup command in version control and diff them on every deploy.
6
Gate slot swaps on a real warmup health check so a dead worker can never become production.

Common mistakes to avoid

5 patterns
×

Deploying a framework-dependent app without pinning the App Service runtime

Symptom
The app runs for months, then a platform update or a slot swap changes the available runtime and startup dies overnight. Nobody deployed anything, yet the site is down and the team blames Azure.
Fix
Deploy with the runtime explicit: set the stack and version in the portal's Configuration blade or with az webapp config set --linux-fx-version. Better yet, publish self-contained so the app carries its own runtime and stops depending on the platform's installed SDKs.
×

Guessing at the crash instead of turning on stdout logging

Symptom
Engineers redeploy three times with different theories while the actual exception sits unread in a log file. Every redeploy resets the evidence and the cycle repeats.
Fix
Turn on Application Logging (Filesystem) plus Detailed Error Messages before you touch code: az webapp log config --application-logging filesystem --detailed-error-messages true. Reproduce, read Log Stream, then fix the named exception.
×

Reading secrets from appsettings.json files that never ship

Symptom
Works on every laptop, crashes in Azure with a null connection string. The publish profile excluded the local settings file, so the app throws on the first database call during startup.
Fix
Move every secret and connection string into App Service app settings (backed by Key Vault references in production) and validate required settings at startup with a loud, specific error message naming the missing key.
×

Letting web.config or the Linux startup command drift out of version control

Symptom
A manual portal tweak fixes startup once, then the next deploy overwrites it and 502.5 returns. The team argues about what changed because the working config was never committed anywhere.
Fix
Keep web.config (Windows) or the startup command (Linux) under version control and diff it on every deploy. For Linux, set the startup command explicitly in Configuration rather than relying on defaults that change between stacks.
×

Swapping slots without warming up the staging slot first

Symptom
The swap promotes a worker that never actually started, and production goes down at the moment you expected safety. The staging slot showed green because nobody ever sent it a real request.
Fix
Always warm up the staging slot with health checks after a swap-targeted deploy, and configure auto-swap only after the warmup path is proven. Roll back with a re-swap the moment health checks fail.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What does HTTP error 502.5 mean on Azure App Service?
Q02JUNIOR
Walk me through finding the crash behind a 502.5.
Q03SENIOR
Your stdout log says the framework was not found. What happened and how ...
Q04SENIOR
What is ANCM and how does it relate to 502.5 on Windows?
Q05SENIOR
Design a deploy pipeline where a startup crash can never reach productio...
Q01 of 05JUNIOR

What does HTTP error 502.5 mean on Azure App Service?

ANSWER
It means the app process failed while starting, so the front end has nothing to forward requests to. The platform is healthy; your code crashed before listening. The first move is enabling application logging and reading stdout output, which usually names the exception within seconds of a restart.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Is a 502.5 an Azure outage?
02
Where do I find the actual crash message?
03
Framework-dependent vs self-contained: which avoids 502.5?
04
How do I check which runtime my App Service really runs?
05
Does restarting the App Service fix 502.5?
06
How do I stop a bad deploy from reaching production?
N
Naren Founder & Principal Engineer

20+ years shipping production backend systems. Drawn from code that ran under real load.

Follow
✓ Verified
production tested
September 26, 2026
last updated
2,085
articles · all by Naren
🔥

That's Azure. Mark it forged?

6 min read · try the examples if you haven't

←
Previous
Azure AADSTS700016: Application Not Found in Directory
2 / 4 · Azure
Next
Azure AKS ImagePullBackOff From ACR — Missing Role
→