Skip to content

[perf] Synchronous console.error of the full response body on every HTTP 500 #9

Description

@MrSociety404

Problem

HTTPResult.setStatus calls console.error(this.body) whenever status is 500 (lines 105-107); because the constructor calls setBody before setStatus, new HTTPResult(500, body) logs the entire already-serialized JSON body. console.error writes synchronously to stderr for TTY and file destinations (and many production log sinks), which blocks the event loop for the duration of the write, and it re-emits the full (potentially large) body string.

Location: src/index.ts:106
Severity: 🟢 low
Category: event-loop-blocking

Performance impact

Normally harmless because 500s should be rare, but during an error storm — e.g. a downstream dependency outage causing most requests to return 500 — this performs a synchronous, full-body stderr write on essentially every request, blocking the event loop and amplifying the incident (throughput collapse) exactly when the server is already under stress. Large error payloads make each blocking write longer.

Suggested fix

Make setStatus a pure setter (remove the console.error entirely). Do error logging once at the point the response is actually emitted (sendResponse/sendHeadResponse) or in the request pipeline where the thrown error/context is available, using the framework's already-imported async Logging facility (e.g. Logging.Error) instead of synchronous console.error. Include request context (method/path/error) rather than only the raw body, gate it so expected/handled 500s aren't spammed, avoid re-logging if setStatus(500) is called more than once, and truncate/size-limit the body (and consider redaction) since it may be large or contain sensitive data.

Verification notes

Confirmed at src/index.ts:105-107 that setStatus performs I/O (console.error(this.body)) inside a plain state setter, and the constructor (93-96) runs setBody before setStatus so the full serialized body is logged on every new HTTPResult(500, …); the tests (index.test.ts:890-893) show 500s are produced whenever a handler throws, so a downstream outage funnels every failing request through this line. The impact is real but bounded — Node's stderr write is synchronous only for TTY/file sinks (async for the pipes common in container deployments) and a single-line write is small — so "throughput collapse" is overstated, but doing synchronous, context-free, full-body logging in a setter on the error hot path is a legitimate defect worth fixing, especially since the framework already exposes an async Logging facility used elsewhere.


Found by an automated AI performance review (multi-agent analysis + independent adversarial verification of each finding).

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance improvement

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions