A production 500 error is a symptom, not a diagnosis. For a CTO or founder, the first decision is whether to stabilize traffic, roll back a recent change, or investigate an ongoing failure. Preserve the evidence before changing limits or restarting everything. This guide separates PHP and Node.js failure modes, gives a practical diagnostic list, and defines a safe recovery path.

First response: stabilize, preserve, assign

Start with impact and timing rather than a guessed root cause. Name an incident owner, record the first failed request and last known-good release, and keep one shared timeline.

  1. Assess blast radius: Which routes, tenants, regions and workflows fail? Check error rate, latency and health checks against the baseline. A 500 from the application differs from a proxy 502/504 or a client timeout.
  2. Protect data and evidence: Capture deployment ID, configuration changes, request IDs, sanitized stack traces, process/container restarts, memory graphs and upstream dependency health. Restrict access to logs and redact tokens and personal data.
  3. Contain safely: If the spike follows a release, use the tested rollback path or disable the implicated feature flag. Verify schema compatibility before rolling back code; a database migration may not be reversible. Avoid deleting logs, broad permission changes and repeated blind restarts.
  4. Communicate: State what is affected, mitigation, owner and next update time. Do not claim a root cause until evidence supports it.

Diagnostic list: signal, likely area, first check

  • HTTP 500: Application exception, PHP fatal error or failed dependency. Correlate a request ID and timestamp across proxy, application and database logs; compare with the latest release. Confirm which layer generated the status.
  • Memory exhaustion: In PHP, look for an “Allowed memory size exhausted” fatal and inspect the effective memory_limit for the relevant SAPI. In Node.js, distinguish V8 heap pressure from process RSS and container memory limits; review heapUsed, RSS and restart/OOM events over time.
  • Timeout: Identify who timed out: browser, load balancer, web server, PHP execution, Node client, database or external API. Compare deadline settings with actual request traces; investigate slow queries, blocked I/O and queue saturation before raising a timeout.
  • Node EADDRINUSE: The requested address/port is already occupied. Inspect the configured port and process inventory under your deployment tooling; check for duplicate listeners or overlapping rollout processes. Do not kill an unknown process merely to free a port.
  • Unhandled promise rejection: Find the rejected operation and its stack/context. Add explicit handling at the async boundary, distinguish recoverable request errors from process-fatal state, and review the runtime's unhandled-rejection behavior. An event listener is not a substitute for handling the originating failure.
  • Log silence or mismatch: Confirm that the relevant worker, container and time window are being queried; check log routing, retention and clock skew. A missing application entry can mean the request failed upstream or the process died before logging.

PHP: error reporting, limits and the request lifecycle

PHP applications commonly run behind a web server and a process manager such as PHP-FPM, so check the web-server error log and the correct PHP worker/pool log, not only the page response. PHP's error_reporting controls which error levels are reported; log_errors and error_log control logging, while display_errors should not expose diagnostics to production users. Confirm the effective configuration in the same execution context as the failing request, because CLI and web SAPIs can load different configuration.

The core memory_limit and max_execution_time settings can explain a fatal error or time limit, but raising them without measuring the workload may hide an unbounded query or loop. The web server, PHP-FPM request termination, database and reverse proxy may each impose separate deadlines. Review recent dependency updates, file permissions, autoload errors, and connection exhaustion alongside the stack trace.

Node.js: process failures are not PHP request failures

A Node.js service is a long-running process. A thrown error, rejected promise, bind failure or exhausted heap can terminate it and affect many requests until the supervisor replaces it. Node error objects expose a stable code for system errors such as EADDRINUSE; avoid branching on message text. Promise-returning APIs need rejection handling, and callback-style APIs require checking the error argument.

For memory, compare process.memoryUsage() fields such as heapUsed and rss over time, plus container limits and GC behavior. The V8 old-space limit is only one constraint; simply increasing --max-old-space-size can move the failure to the host or container if memory is insufficient. Investigate retained objects, caches without bounds, oversized payloads and concurrency before tuning. Node's documentation explains these memory metrics and tuning controls.

Logs and rollback: make the next action reversible

Use a read-only query in your own logging platform filtered by service, release, request ID and a narrow incident window. Compare the first failing and last successful request, then annotate each intervention. Do not paste production credentials or raw customer data into tickets or AI tools. If logging is incomplete, preserve existing container and platform events before redeploying.

Rollback is appropriate when the onset aligns with a release and the previous artifact is known-good. Revert the application and flag together only if the prior version is compatible with current data and external contracts; otherwise use a targeted mitigation. Validate with a small set of critical user journeys and error-rate/latency graphs, not merely a green health endpoint. Maintain a forward-fix owner and incident timeline even after traffic recovers.

Prevention: turn one incident into an operational control

  • Set alerts for error budget burn, p95 latency, restarts/OOM kills, memory trend, queue depth and dependency failures, with owners and escalation.
  • Use structured, privacy-conscious logs with request IDs and release IDs. Test that an operator can trace a request across proxy, application and database.
  • Set explicit timeouts, backpressure and bounded retries with jitter for downstream calls; avoid retry storms.
  • Test a release rollback and restore in a non-production environment, and document schema compatibility and feature-flag controls.
  • Reproduce the failure with a focused regression test, review resource limits under realistic load, and write a blameless post-incident note with a named owner and due date.

When to bring in an engineering partner

Escalate when the team cannot reproduce the release, identify account ownership, access the right logs, or safely restore service. For a live application, the useful output is an evidence-backed diagnosis, risk-ranked remediation and a repeatable deployment/rollback runbook, not an unsupported promise to “fix every 500.” Nextchain describes its web application development and ongoing development capabilities, including work on existing applications. If an incumbent vendor holds the operational knowledge, use the vendor handover checklist to secure code, accounts and recovery procedures. Request a project assessment with symptoms, impact and constraints, but do not submit credentials or sensitive production data.

Frequently asked questions

Should we turn on PHP display_errors in production?

No. Keep detailed diagnostics in access-controlled logs and avoid showing stack traces, paths or secrets to end users. Verify the effective PHP configuration for the affected worker.

Does an HTTP 500 mean PHP or Node.js is broken?

No. It only means the server failed to fulfill the request. Identify whether the response came from the proxy, application or upstream dependency before assigning a cause.

Will more memory or a longer timeout fix the incident?

It may buy time only after capacity and safety checks. First identify whether the workload is legitimately larger, a leak, a slow query or an unavailable dependency. Monitor the effect and keep a rollback plan.

When is rollback unsafe?

When a new schema, data format or external integration is incompatible with the old code. Use a rehearsed compatibility plan or targeted mitigation instead of assuming the previous binary can run unchanged.

Official references