Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Return generic errors to clients; keep detail in logs with a correlation id
Send clients a generic message and a correlation/request id. Never serialize raw exception messages, stack traces, DB errors, or upstream error bodies into the HTTP response.
Bad example
| 1 | // Express error handler |
| 2 | app.use((err, req, res, next) => { |
| 3 | res.status(500).json({ error: err.message, stack: err.stack }); // leaks internals |
| 4 | }); |
| 5 |
|
| 6 | // or ad-hoc in a route |
| 7 | catch (err) { |
| 8 | return res.status(500).json({ message: 'DB error', detail: err }); // serializes the whole error |
| 9 | } |
Explanation (EN)
Returning `err.message`/`err.stack` exposes file paths, framework and library versions, SQL fragments, and sometimes leaked data values straight to the attacker. It turns every 500 into reconnaissance. Serializing the whole `err` can also drag in request config containing tokens. This is OWASP A05 (Security Misconfiguration) / information disclosure.
Objašnjenje (HR)
Vraćanje `err.message`/`err.stack` izlaže putanje datoteka, verzije frameworka i biblioteka, SQL fragmente i ponekad procurene vrijednosti podataka izravno napadaču. Svaki 500 pretvara u izviđanje. Serijalizacija cijelog `err` može povući i konfiguraciju zahtjeva koja sadrži tokene. Ovo je OWASP A05 / otkrivanje informacija.
Good example
| 1 | // Express error handler |
| 2 | app.use((err, req, res, next) => { |
| 3 | const correlationId = req.id ?? crypto.randomUUID(); |
| 4 | logger.error({ err: err.message, stack: err.stack, correlationId }, 'unhandled error'); |
| 5 | res.status(500).json({ |
| 6 | error: 'Something went wrong. Please try again.', |
| 7 | correlationId, // lets support map the user report to the log line |
| 8 | }); |
| 9 | }); |
Explanation (EN)
The client receives a stable, non-revealing message plus a correlation id; the full detail goes to the log where access is controlled. Support and engineers can trace the exact failure via the id without exposing internals to the public. The asymmetry — generic out, detailed in — is the whole point.
Objašnjenje (HR)
Klijent prima stabilnu, neotkrivajuću poruku i korelacijski id; potpuni detalj ide u log gdje je pristup kontroliran. Podrška i inženjeri mogu pratiti točan kvar preko id-a bez izlaganja interne strukture javnosti. Asimetrija — generičko van, detaljno unutra — je cijela poanta.
Exceptions / Tradeoffs (EN)
Validation errors (400) may and should be specific about which field failed and why, since that is actionable for the legitimate caller and reveals nothing internal. The generic-message rule applies to 500-class and unexpected errors.
Iznimke / Tradeoffi (HR)
Validacijske pogreške (400) smiju i trebaju biti specifične o tome koje je polje palo i zašto, jer je to korisno legitimnom pozivatelju i ne otkriva ništa interno. Pravilo generičke poruke odnosi se na pogreške klase 500 i neočekivane pogreške.