---
description: "CodeWiki Backend pitfalls and review checks"
globs: []
alwaysApply: false
---

# Backend rules

This track covers more than one language, so no file globs are inferred. Apply these rules manually when they are relevant.

- The server defaults an omitted version to the newest implementation.
  Why: An old client that never sent a selector then changes behavior on the day a new version ships.
  Source: [API versioning](https://codewiki.com/backend/api-versioning/)
- Do not assume this is safe: a team labels every deployment `v1.2.17` and assumes Semantic Versioning proves client compatibility.
  Why: Operational releases and public protocol versions become coupled, while behavioral changes escape review because the major digit did not move.
  Source: [API versioning](https://codewiki.com/backend/api-versioning/)
- Do not assume this is safe: header-based versions return different representations under one URI, but cache configuration ignores the selecting header.
  Why: A shared cache can then serve a v1 response to a v2 request.
  Source: [API versioning](https://codewiki.com/backend/api-versioning/)
- Each version receives a copied controller, service, repository, and database query.
  Why: Fixes land in the newest tree while security and correctness defects survive in older supported versions.
  Source: [API versioning](https://codewiki.com/backend/api-versioning/)
- Do not assume this is safe: a deprecation date is chosen from a calendar without knowing who still calls the version.
  Why: The loud announcement reaches active developers but misses unattended jobs and integrations owned by another team.
  Source: [API versioning](https://codewiki.com/backend/api-versioning/)
- Do not assume this is safe: the team writes OpenAPI first but lets routes and responses merge without contract checks.
  Why: Within weeks, the specification describes the plan while production runs a different interface.
  Source: [API-first design](https://codewiki.com/backend/api-first/)
- Generated code is treated as the design result.
  Why: A generator faithfully amplifies vague names, permissive schemas, and missing error responses, while regeneration may overwrite hand edits.
  Source: [API-first design](https://codewiki.com/backend/api-first/)
- The mock always returns the example success response.
  Why: The client never implements authentication failures, validation errors, empty results, or unknown status handling until it reaches the real provider.
  Source: [API-first design](https://codewiki.com/backend/api-first/)
- Do not assume this is safe: verification checks only the JSON response body and ignores status, `Content-Type`, `Location`, caching fields, or authentication challenges.
  Why: Clients depend on the whole HTTP exchange, so an object schema alone misses protocol defects.
  Source: [API-first design](https://codewiki.com/backend/api-first/)
- Every added field is classified as safe, or every specification diff is classified as breaking.
  Why: Actual compatibility depends on the direction of the change, consumer tolerance, and promised semantics.
  Source: [API-first design](https://codewiki.com/backend/api-first/)
- Successful JSON parsing proves only valid syntax.
  Why: Fields may be missing, wrongly typed, too long, or include a caller-controlled `ownerId`; spreading the whole object into a database record also creates a mass-assignment problem.
  Source: [Backend development](https://codewiki.com/backend/getting-started/)
- An in-memory array is handy in a demonstration, but worker processes don't share it and a restart erases it.
  Why: Read-then-write checks can also pass simultaneously under concurrency.
  Source: [Backend development](https://codewiki.com/backend/getting-started/)
- Do not assume this is safe: if the response goes out first, a later database write or event publication can fail after the client has received an irrevocable success.
  Why: Conversely, a connection can fail after commit, and a blind retry may duplicate the effect.
  Source: [Backend development](https://codewiki.com/backend/getting-started/)
- Always returning `200` with `success: false` in the body prevents generic HTTP clients, caches, and monitoring from interpreting the result.
  Why: Turning every exception into `500` instead mixes caller errors with service failures.
  Source: [Backend development](https://codewiki.com/backend/getting-started/)
- Middleware order has semantics.
  Why: Authorization has no trusted principal if it runs before authentication; an error handler that doesn't wrap later handlers yields different error shapes on different paths.
  Source: [Backend development](https://codewiki.com/backend/getting-started/)
- Orchestrators and load balancers call health endpoints frequently.
  Why: A probe that creates records, sends messages, or runs expensive queries can change business state or amplify an outage.
  Source: [Backend development](https://codewiki.com/backend/getting-started/)
- A converter proves that `/orders/42/` contains an integer.
  Why: It does not prove that the current user may read order 42.
  Source: [Django](https://codewiki.com/backend/django/)
- Iterating a QuerySet and then reading an uncached relation can issue one extra query per result, producing the N+1 query pattern.
  Source: [Django](https://codewiki.com/backend/django/)
- Form or serializer validation runs in one application path, while scripts, admin actions, concurrent requests, and bulk operations may write through another path.
  Source: [Django](https://codewiki.com/backend/django/)
- Do not assume this is safe: declaring a view `async def` does not make synchronous ORM calls, network clients, or middleware nonblocking.
  Why: It can instead add context switches or raise an async-safety error.
  Source: [Django](https://codewiki.com/backend/django/)
- Do not assume this is safe: `runserver`, `DEBUG=True`, a source-controlled `SECRET_KEY`, and permissive host or origin settings are development conveniences, not a production configuration.
  Source: [Django](https://codewiki.com/backend/django/)
- Generated code often treats `body as CreateOrder` as input validation; the assertion changes only the compiler's view and checks no field at runtime.
  Source: [Elysia](https://codewiki.com/backend/elysia/)
- Saving `const app = new Elysia()` and then adding routes in detached statements leaves the exported variable's type at the empty application.
  Source: [Elysia](https://codewiki.com/backend/elysia/)
- An authentication hook placed after a route normally doesn't retroactively protect it, and a plugin's local hook doesn't automatically protect routes later registered on the parent.
  Source: [Elysia](https://codewiki.com/backend/elysia/)
- A generated handler may return `{ error: ...
  Why: }` under `200`, or mutate `set.status` and return an object that doesn't satisfy that status's response schema.
  Source: [Elysia](https://codewiki.com/backend/elysia/)
- Do not assume this is safe: a locally compiling Eden client proves only that it matches the application type present at build time, not that the target URL runs the same service version.
  Source: [Elysia](https://codewiki.com/backend/elysia/)
- If the route-definition module calls `.listen()` during import, tests, scripts, and type consumers acquire port and process side effects.
  Source: [Elysia](https://codewiki.com/backend/elysia/)
- Do not treat `value: str | None` as an optional request parameter.
  Why: The union allows `None` as a value, but it doesn't automatically let the client omit the parameter.
  Source: [FastAPI](https://codewiki.com/backend/fastapi/)
- Do not assume this is safe: returning a database object or input model without declaring a public response model.
  Why: Generated code can thereby serialize a password hash, internal note, or tenant identifier.
  Source: [FastAPI](https://codewiki.com/backend/fastapi/)
- Calling a blocking database driver, synchronous HTTP client, or `time.sleep()` inside an `async def` path operation.
  Why: An async function name doesn't turn its internal blocking operations into points where control can be yielded.
  Source: [FastAPI](https://codewiki.com/backend/fastapi/)
- Do not treat Pydantic validation as authorization.
  Why: `order_id: int` proves only that the input parses as an integer, not that the current principal may read that order.
  Source: [FastAPI](https://codewiki.com/backend/fastapi/)
- Do not assume this is safe: setting `app.dependency_overrides` in a test without restoring it.
  Why: Later tests can keep using a fake user or session, making results depend on test order.
  Source: [FastAPI](https://codewiki.com/backend/fastapi/)
- An allowlist based only on the extension or client `Content-Type` treats attacker-controlled metadata as proof of content.
  Source: [File uploads](https://codewiki.com/backend/file-upload/)
- Joining the original filename into a local path, object key, or public URL creates path traversal, overwrite, special-name, and encoding hazards.
  Source: [File uploads](https://codewiki.com/backend/file-upload/)
- `await file.arrayBuffer()`, `Buffer.concat(chunks)`, or unbounded concurrency lets a small number of connections exhaust heap, temporary disk, or file descriptors.
  Source: [File uploads](https://codewiki.com/backend/file-upload/)
- Do not assume this is safe: a successful byte write or object-store response does not mean the file passed authorization, integrity, content, and malware checks.
  Source: [File uploads](https://codewiki.com/backend/file-upload/)
- Do not assume this is safe: retrying initialization, a part, or completion without a stable session identity and idempotency rules creates duplicate records, overwritten objects, or parts that are never reclaimed.
  Source: [File uploads](https://codewiki.com/backend/file-upload/)
- Calling `app.run(debug=True)` in production enables a development-only server and interactive debugger.
  Why: The debugger can execute Python code, and its PIN isn't a security boundary. Fix: Load the factory with a supported production WSGI server and disable debug mode explicitly in deployment configuration. Configure trusted hosts, TLS, and forwarded headers correctly behind a proxy; don't trust client-supplied `X-Forwarded-*` headers directly.
  Source: [Flask](https://codewiki.com/backend/flask/)
- Do not treat `request.get_json()` as a dictionary and checking only for field presence misses a wrong media type, malformed JSON, an array at the top level, `null`, booleans masquerading as integers, and unknown fields.
  Why: Generated code copied from older examples may also expect an incorrect media type to produce `400`, while current Flask uses `415`. Fix: Define the media type, top-level shape, field types, ranges, and unknown-field policy before mapping validation failures to stable error responses. Test an empty body, wrong `Content-Type`, malformed JSON, and type boundaries, not only the successful object.
  Source: [Flask](https://codewiki.com/backend/flask/)
- Do not assume this is safe: reading `request`, `session`, `g`, or `current_app` after the request ends, in a background thread, or in a task worker resolves against the wrong context or raises `RuntimeError: Working outside of request context.` Passing the proxy itself to another execution unit doesn't copy its current target.
  Why: Fix: Copy the scalar or immutable values the job actually needs while the request is active, then pass them explicitly to background code. Use `with app.app_context():` in non-request code only when it genuinely needs application resources; don't use a manual context to hide missing function parameters.
  Source: [Flask](https://codewiki.com/backend/flask/)
- Do not register routes, blueprints, error handlers, or extensions after the application starts handling requests; doing so can leave worker processes with different setups.
  Why: Flask rejects some late setup operations, but it can't prove that external initialization ran identically in every process. Fix: Complete all application setup in the factory before handing the application to a server. Database migrations and one-time data preparation should be separate deployment steps, not “first request” hooks; `before_first_request` has been removed from current Flask.
  Source: [Flask](https://codewiki.com/backend/flask/)
- Do not assume this is safe: seeing `async def` and assuming Flask has become an ASGI service leads to incorrect capacity estimates.
  Why: Under WSGI, each async view still occupies one worker, incomplete `asyncio` tasks spawned by the view are cancelled when it returns, and synchronous extensions may still block. Fix: Use Flask async views only to await supported asynchronous I/O concurrently within a view, and install `flask[async]`. Send durable background work to a task queue. If long-lived connections or async concurrency dominate, verify an ASGI design against the actual server.
  Source: [Flask](https://codewiki.com/backend/flask/)
- Reading `next` from a query parameter and passing it directly to `redirect(next_url)` creates an open redirect.
  Why: An attacker can construct a login link that sends a user to an external imitation site. Fix: Accept only local relative targets by parsing and validating the scheme, host, and allowed path; fall back to a named internal endpoint on failure. Test scheme-relative URLs, encoded backslashes, repeated encoding, and nondefault ports, not only a normal `/dashboard` value.
  Source: [Flask](https://codewiki.com/backend/flask/)
- The schema proves only that fields and arguments are type-valid.
  Why: An attacker can still submit someone else's order ID or reach the same sensitive object through another query path.
  Source: [GraphQL](https://codewiki.com/backend/graphql/)
- A shallow operation can still exhaust resources through many aliases, expensive fields, and huge list arguments.
  Why: A fixed depth also can't express that two fields have very different costs.
  Source: [GraphQL](https://codewiki.com/backend/graphql/)
- Once a list field returns N objects, a child resolver that makes one backend call per object creates an N+1 access pattern.
  Why: With one or two fixture rows, the code looks perfectly healthy.
  Source: [GraphQL](https://codewiki.com/backend/graphql/)
- Do not assume this is safe: mapping a non-optional TypeScript property or database `NOT NULL` directly to GraphQL Non-Null ignores authorization redaction, remote failures, and bad historical data.
  Why: One missing leaf can erase an object or even the root data.
  Source: [GraphQL](https://codewiki.com/backend/graphql/)
- Serial execution of top-level mutation fields defines only their execution order.
  Why: It doesn't place multiple database writes in a transaction, undo earlier side effects when a later field fails, or make a network retry idempotent.
  Source: [GraphQL](https://codewiki.com/backend/graphql/)
- Removing a field, changing its type, or adding a required argument to an existing field breaks deployed operations.
  Why: Adding an enum value is usually additive, yet it can still break an exhaustive client branch.
  Source: [GraphQL](https://codewiki.com/backend/graphql/)
- Generated clients make call syntax look local, which tempts code to omit deadlines, cancellation handling, and partial-failure design.
  Why: A network call can also lose its response after the server completes.
  Source: [gRPC](https://codewiki.com/backend/grpc/)
- Giving a removed field number a new meaning lets new code misread old messages.
  Why: Renaming while keeping the number usually preserves binary identity, but JSON mapping, reflection, and operational tools can still change.
  Source: [gRPC](https://codewiki.com/backend/grpc/)
- Do not assume this is safe: `UNAVAILABLE` means temporarily unavailable; it doesn't prove that the server skipped the request.
  Why: Automatically retrying a non-idempotent charge or reservation can duplicate the side effect.
  Source: [gRPC](https://codewiki.com/backend/grpc/)
- Receiving `authorization` or `tenant-id` metadata doesn't make it trustworthy.
  Why: A generated interceptor that parses fields without validating signature and audience lets a caller forge an identity or tenant.
  Source: [gRPC](https://codewiki.com/backend/grpc/)
- Collecting an entire client stream into a slice before processing lets the caller control server memory.
  Why: A server stream that ignores blocked sends and cancellation can also strand a growing number of goroutines.
  Source: [gRPC](https://codewiki.com/backend/grpc/)
- Business logic added to a generated client or message type may compile today but disappears on regeneration.
  Why: Generated clients in other languages won't receive it either.
  Source: [gRPC](https://codewiki.com/backend/grpc/)
- `await c.req.json()` and type assertions only change the compiler's view.
  Why: An attacker can still send missing fields, wrong types, out-of-range numbers, or extra fields, while generated code may pass them directly to the database.
  Source: [Hono](https://codewiki.com/backend/hono/)
- Hono registration order has semantics.
  Why: Authentication or validation middleware registered too late may never cover earlier routes, while a missing `await next()` unexpectedly cuts off the entire later chain.
  Source: [Hono](https://codewiki.com/backend/hono/)
- A route using only `Request` and `Response` doesn't mean database drivers, file systems, cryptography, environment values, or background work have the same API and lifecycle on every runtime.
  Source: [Hono](https://codewiki.com/backend/hono/)
- A module-level `Map` is useful in a deterministic example, but it cannot store orders, rate-limit counters, or session facts.
  Why: Instances have separate copies, restarts lose the contents, and read-then-write updates can race.
  Source: [Hono](https://codewiki.com/backend/hono/)
- `hc` checks only the application type available when the client compiles.
  Why: An old service, a stale client declaration, a non-TypeScript caller, or a wrong runtime response body can all drift without the type system detecting it.
  Source: [Hono](https://codewiki.com/backend/hono/)
- `POST /createOrder`, `GET /getOrder`, and `POST /deleteOrder` repeat method intent in the path and can let a safe method trigger a mutation by accident.
  Source: [HTTP API design](https://codewiki.com/backend/api-design/)
- `{ "success": false }` with `200 OK` makes caches, retry logic, metrics, and generated clients misclassify the result, while every caller must parse a custom envelope.
  Source: [HTTP API design](https://codewiki.com/backend/api-design/)
- Do not assume this is safe: an idempotent method does not prove that a request arrived or require repeated responses to match; adding an `Idempotency-Key` header to `POST` also creates no deduplication by itself.
  Source: [HTTP API design](https://codewiki.com/backend/api-design/)
- Two clients can read one representation and make separate edits.
  Why: An unconditional `PATCH` lets the later commit overwrite the earlier one while both callers receive success.
  Source: [HTTP API design](https://codewiki.com/backend/api-design/)
- `model.update(request.body)` writes unknown caller-supplied fields too.
  Why: Generated handlers often expose immutable properties such as `role`, `ownerId`, balances, or internal state.
  Source: [HTTP API design](https://codewiki.com/backend/api-design/)
- A list with `limit` and `offset` but no fixed order can reshuffle between calls.
  Why: Ordering by a non-unique field alone can also duplicate or omit records at page boundaries.
  Source: [HTTP API design](https://codewiki.com/backend/api-design/)
- Creating a new `Client` or `AsyncClient` for every call shortens the connection pool's life to one request.
  Why: Generated code particularly often puts `AsyncClient()` inside a coroutine that handles one record, then creates many clients concurrently without reusing connections.
  Source: [HTTPX](https://codewiki.com/backend/httpx/)
- Do not assume this is safe: hTTPX's default five-second rule concerns network inactivity; it does not guarantee that a full download or several retries finish within five seconds.
  Why: A server that keeps returning slow chunks can continually refresh the read timeout.
  Source: [HTTPX](https://codewiki.com/backend/httpx/)
- `client.get()` still returns a `Response` when it receives `500`.
  Why: If generated code immediately calls `.json()` and reads the success schema, the protocol error becomes a `KeyError`, a wrong default, or bad cached data.
  Source: [HTTPX](https://codewiki.com/backend/httpx/)
- An early return, parse exception, or task cancellation can bypass a handwritten close call and keep the connection occupied.
  Why: The failure often appears only after concurrency rises and the pool is exhausted, as a `PoolTimeout`.
  Source: [HTTPX](https://codewiki.com/backend/httpx/)
- Do not assume this is safe: a `ReadTimeout` only says that the client did not receive the next data chunk in time; it does not prove the server skipped the request.
  Why: Blindly retrying `POST` can create duplicate orders, charges, or messages.
  Source: [HTTPX](https://codewiki.com/backend/httpx/)
- Do not assume this is safe: more coroutines do not remove connection limits, upstream rate limits, or server capacity.
  Why: Unbounded fan-out only adds queues, memory, and cancellation cost and may trigger `429` responses.
  Source: [HTTPX](https://codewiki.com/backend/httpx/)
- Code decodes the payload first and puts its `sub` or `role` into the request context.
  Why: Decoding proves no origin, and an attacker can rewrite every claim.
  Source: [JWT authentication](https://codewiki.com/backend/jwt-authentication/)
- Code treats `alg`, `kid`, `jku`, or `x5u` as trusted configuration.
  Why: Generated implementations often select an algorithm from `alg`, concatenate `kid` into a file path or query, or fetch the key URL supplied by the token.
  Source: [JWT authentication](https://codewiki.com/backend/jwt-authentication/)
- Code verifies only the signature and `exp`.
  Why: A valid JWT issued for another API, tenant, or token kind can then be accepted by this endpoint.
  Source: [JWT authentication](https://codewiki.com/backend/jwt-authentication/)
- A bearer token appears in a URL, ordinary application log, or analytics event.
  Why: Reverse proxies, browser history, monitoring, and error tracking can copy data from those locations.
  Source: [JWT authentication](https://codewiki.com/backend/jwt-authentication/)
- Do not assume this is safe: a design assumes HttpOnly cookies eliminate XSS, or that local storage automatically eliminates CSRF.
  Why: HttpOnly stops scripts from reading a cookie, but an active malicious script can still send requests. Automatically attached cookies create a CSRF boundary.
  Source: [JWT authentication](https://codewiki.com/backend/jwt-authentication/)
- Logout only deletes the client's copy.
  Why: A copied access token remains valid to the server until it expires or matches a server-side revocation rule.
  Source: [JWT authentication](https://codewiki.com/backend/jwt-authentication/)
- Path parameters, headers, and decoded fields come from untrusted clients.
  Why: Using `!!` to silence a compiler error turns missing input into a `NullPointerException` with no defined protocol response.
  Source: [Kotlin backend development](https://codewiki.com/backend/kotlin-backend/)
- Work created by `GlobalScope.launch` no longer belongs to the request or application lifetime.
  Why: It may continue after disconnect, shutdown, or parent failure, yet disappear when the process exits.
  Source: [Kotlin backend development](https://codewiki.com/backend/kotlin-backend/)
- Adding `suspend` doesn't change the blocking behavior of JDBC, file APIs, or an old SDK.
  Why: Calling them directly on a constrained request executor holds resources needed by other requests.
  Source: [Kotlin backend development](https://codewiki.com/backend/kotlin-backend/)
- A broad `catch (e: Exception)` that turns `CancellationException` into an ordinary `500` or fallback can let a cancelled request continue into side effects.
  Why: A later suspension may throw cancellation again, making the path harder to reason about.
  Source: [Kotlin backend development](https://codewiki.com/backend/kotlin-backend/)
- Sharing one type among requests, database entities, and responses can expose internal fields and turn a database migration into an API change.
  Why: `copy()` is shallow too, so it doesn't isolate nested mutable state.
  Source: [Kotlin backend development](https://codewiki.com/backend/kotlin-backend/)
- An in-memory map coordinates only requests in one process.
  Why: Restarts lose entries, instances don't share them, and a check-then-write sequence can still let concurrent retries create two results.
  Source: [Kotlin backend development](https://codewiki.com/backend/kotlin-backend/)
- Do not assume this is safe: a route parameter resolving to a model and request fields passing rules do not mean the current user may read or modify the object.
  Why: Generated code often stops at `findOrFail()`, letting any authenticated user try IDs from another tenant.
  Source: [Laravel](https://codewiki.com/backend/php-laravel/)
- `$model->update($request->all())` turns every transport key into a candidate write.
  Why: Even if today's `$fillable` list happens to be safe, a later fillable field can expose a privilege, price, or state transition.
  Source: [Laravel](https://codewiki.com/backend/php-laravel/)
- Caching the current user, request, or tenant in a `singleton()` may appear harmless under a short PHP-FPM lifecycle.
  Why: Once Octane or a queue worker reuses the application, that state can leak across requests or jobs.
  Source: [Laravel](https://codewiki.com/backend/php-laravel/)
- A controller may execute only one `Order::paginate()`, while `$order->customer->name` inside a template loop issues another query for every order.
  Why: Resource serialization, logging, and debug output can trigger relationship access too.
  Source: [Laravel](https://codewiki.com/backend/php-laravel/)
- Generated code often calls `env('PAYMENT_KEY')` in a controller or service.
  Why: After `config:cache`, Laravel no longer loads the `.env` file, so application code may receive `null` or a different value from the external system environment.
  Source: [Laravel](https://codewiki.com/backend/php-laravel/)
- Requests has no timeout by default.
  Why: One numeric value sets both connect and read timeouts, but a read timeout measures how long the socket receives no bytes; it is not a deadline for the whole download.
  Source: [Requests](https://codewiki.com/backend/requests/)
- Do not assume this is safe: `response.json()` can successfully decode a `500` error response and can fail on `204`, an HTML gateway error, or truncated content.
  Why: Parseable JSON and business success are separate facts.
  Source: [Requests](https://codewiki.com/backend/requests/)
- Copying `allowed_methods=None` into `Retry` makes every method eligible for replay.
  Why: If a `POST` created an order but its response was lost, the second call may create another one.
  Source: [Requests](https://codewiki.com/backend/requests/)
- `verify=False` stops certificate verification, so the client cannot authenticate its peer.
  Why: Hiding `InsecureRequestWarning` hides the signal without restoring authentication.
  Source: [Requests](https://codewiki.com/backend/requests/)
- A long-lived global `Session` can carry cookies, authentication, or default headers into unrelated calls.
  Why: A `stream=True` response that is neither consumed nor closed also holds a connection and weakens pool reuse.
  Source: [Requests](https://codewiki.com/backend/requests/)
- Passing user input directly to `requests.get()` can cause server-side request forgery (SSRF).
  Why: An attacker may reach loopback, private networks, cloud metadata, or use a redirect to evade the first check.
  Source: [Requests](https://codewiki.com/backend/requests/)
- A plural noun in `/users` doesn't make the interface correct.
  Why: If `GET /users/7` disables the account or every failure returns `200`, intermediaries and clients still act on false semantics.
  Source: [RESTful API design](https://codewiki.com/backend/restful-api-design/)
- Generated code often implements `PUT` as an arbitrary field merge and then claims every `PATCH` is inherently idempotent.
  Why: Patch idempotency depends on the media type and operation: "set the value to 5" and "increment the value" behave differently when repeated.
  Source: [RESTful API design](https://codewiki.com/backend/restful-api-design/)
- "Read, compare in the application, then save" still lets two writers pass the check when those steps aren't atomic.
  Why: Whichever save arrives last silently erases the earlier update.
  Source: [RESTful API design](https://codewiki.com/backend/restful-api-design/)
- Returning `{ ...row }` directly can expose internal notes, costs, soft-delete flags, or another tenant's identifiers.
  Why: Adding a database column can then change the public response without an API review.
  Source: [RESTful API design](https://codewiki.com/backend/restful-api-design/)
- A single-process `Map` can't recognize retries across restarts or replicas.
  Why: Looking up only the key string without binding the caller and request fingerprint can also reveal an old response to another user or reuse one result for different input.
  Source: [RESTful API design](https://codewiki.com/backend/restful-api-design/)
- A cursor containing only `createdAt` isn't a stable boundary because several records can share a timestamp.
  Why: Inserts and deletes between pages can make a client see duplicates or miss entries.
  Source: [RESTful API design](https://codewiki.com/backend/restful-api-design/)
- Neither `params.require(...).permit(...)` nor `Order.find(params[:id])` proves that an order belongs to the current user.
  Why: Generated code often finishes the field allowlist and then updates any supplied ID, creating a broken object-level authorization flaw.
  Source: [Ruby on Rails](https://codewiki.com/backend/ruby-rails/)
- `permit!`, `params.to_unsafe_h`, or a hand-written list of every model column turns client fields directly into candidate writes.
  Why: A later `role`, `price_cents`, or `account_id` column can become exposed without any controller change.
  Source: [Ruby on Rails](https://codewiki.com/backend/ruby-rails/)
- Sending mail or calling a payment service from `after_save` makes an ordinary `save!` trigger external work implicitly.
  Why: If the transaction later rolls back, a job retries, or a bulk import repeats the save, the external system may receive duplicate or invalid requests.
  Source: [Ruby on Rails](https://codewiki.com/backend/ruby-rails/)
- `Order.limit(20)` appears to be one query, but reading `order.customer.name` for each row in a view or serializer can issue 20 more.
  Why: Logging, debug output, and JSON resources can trigger lazy association loading too.
  Source: [Ruby on Rails](https://codewiki.com/backend/ruby-rails/)
- Do not assume this is safe: calling the current `Order` model from a migration makes old migration code depend on future validations, callbacks, default scopes, and column names.
  Why: Replaying the migration into an empty database years later can execute entirely different behavior.
  Source: [Ruby on Rails](https://codewiki.com/backend/ruby-rails/)
- A unit test that calls `controller.update` bypasses routing, parameter encoding, middleware, authentication, exception mapping, and response serialization.
  Why: An action that passes that test can still return the wrong status or expose fields on its real HTTP path.
  Source: [Ruby on Rails](https://codewiki.com/backend/ruby-rails/)
- `std::thread::sleep`, synchronous file I/O, synchronous database drivers, and long CPU loops occupy a runtime worker.
  Why: Other tasks on that worker can't advance until the call returns or yields.
  Source: [Rust backend development](https://codewiki.com/backend/rust-backend/)
- Generated code often acquires a `std::sync::MutexGuard` and then calls an async function.
  Why: The guard may make the handler's Future fail the `Send` requirement, and holding it while waiting can block every request that needs the same state.
  Source: [Rust backend development](https://codewiki.com/backend/rust-backend/)
- `Json` proves that a body deserializes into a struct.
  Why: It doesn't prove that the quantity is sensible, the caller may create an order for the target tenant, or the response omits internal fields. Successful Serde decoding isn't domain validation or object-level authorization.
  Source: [Rust backend development](https://codewiki.com/backend/rust-backend/)
- `timeout` reports a deadline by stopping its wait and dropping the inner Future.
  Why: A remote database, sent request, detached task, or running `spawn_blocking` closure may continue and finish a side effect.
  Source: [Rust backend development](https://codewiki.com/backend/rust-backend/)
- Do not assume this is safe: calling `tokio::spawn` for every input, collecting a request body without a limit, or using an unbounded channel converts a traffic burst into memory growth and downstream overload.
  Why: Rust's memory safety doesn't add backpressure to an under-capacity system.
  Source: [Rust backend development](https://codewiki.com/backend/rust-backend/)
- Old tutorials and generated code may still write `.route("/orders/:id", ...)` or implement a custom extractor with a stale `FromRequestParts` signature.
  Why: Version drift often appears as a long trait error, tempting people to add unrelated `Clone` bounds or lifetime annotations.
  Source: [Rust backend development](https://codewiki.com/backend/rust-backend/)
- JSON decoding into `CreateOrder` proves only that fields could construct that Scala type.
  Why: Blank strings, out-of-range quantities, unauthorized resources, and unwanted extra fields may still cross the boundary.
  Source: [Scala backend development](https://codewiki.com/backend/scala-backend/)
- Scattered calls to `unsafeRunSync()` create hidden execution boundaries.
  Why: Errors and cancellation no longer compose, tests may block, and shutdown cannot tell which work is still running.
  Source: [Scala backend development](https://codewiki.com/backend/scala-backend/)
- `IO(jdbcCall())` delays the JDBC call but doesn't change the fact that it blocks a thread.
  Why: Under concurrency, such calls occupy compute threads and prevent unrelated fibers from progressing.
  Source: [Scala backend development](https://codewiki.com/backend/scala-backend/)
- Calling `parTraverse` on an arbitrary request list may start thousands of operations at once.
  Why: Fibers are lightweight, but they still compete for connections, sockets, memory, and downstream quotas.
  Source: [Scala backend development](https://codewiki.com/backend/scala-backend/)
- Returning a client, connection, or stream from `Resource.use` means its finalizer has already run.
  Why: Calling `allocated` and dropping the release action causes the opposite problem: the resource never closes.
  Source: [Scala backend development](https://codewiki.com/backend/scala-backend/)
- Reusing a database `case class` as both request and response can expose internal fields and turn persistence migrations into API changes.
  Why: Returning database exceptions verbatim may also leak SQL and infrastructure details.
  Source: [Scala backend development](https://codewiki.com/backend/scala-backend/)
- A generated application class placed below controllers or services can start successfully while those components remain undiscovered.
  Why: Moving the class to the unnamed package has the opposite problem and can scan dependencies unexpectedly.
  Source: [Spring Boot](https://codewiki.com/backend/spring-boot/)
- Adding several starters “for later” changes the classpath and can activate servers, security filters, data sources, health contributors, or test infrastructure before the application needs them.
  Source: [Spring Boot](https://codewiki.com/backend/spring-boot/)
- Copying an auto-configured bean into application code or excluding an entire configuration to solve one mismatch can create duplicate candidates or remove unrelated defaults.
  Source: [Spring Boot](https://codewiki.com/backend/spring-boot/)
- Do not assume this is safe: scattered `@Value` fields with string defaults can turn a missing timeout, malformed URL, or zero pool size into a late request failure instead of a clear startup failure.
  Source: [Spring Boot](https://codewiki.com/backend/spring-boot/)
- Setting `management.endpoints.web.exposure.include=*` can expose environment, bean, mapping, log, or diagnostic data beyond the operators who need it.
  Source: [Spring Boot](https://codewiki.com/backend/spring-boot/)
- Calling a controller method directly misses binding, validation, filters, converters, and error mapping; a mocked MVC test still misses the server, proxy, and deployed artifact.
  Source: [Spring Boot](https://codewiki.com/backend/spring-boot/)
- Do not treat inferred types as runtime validation.
  Why: A generated procedure accepts `input as CreateOrderInput` or omits `.input()`, assuming the client type makes malformed requests impossible. Casts and network callers bypass that assumption. Fix it by attaching a runtime schema at every untrusted boundary. Test wrong primitive types, extra or missing fields, size limits, and validator transforms through the deployed adapter, not only through a typed caller.
  Source: [tRPC](https://codewiki.com/backend/trpc/)
- Do not assume this is safe: checking authentication but not object authorization.
  Why: A `protectedProcedure` proves somebody signed in; it doesn't prove that `input.accountId`, `orderId`, or `tenantId` belongs to that principal. Derive tenant identity from context and bind it to the query or update predicate. Keep server-owned fields such as role, price, owner, and approval state out of caller-controlled spread objects.
  Source: [tRPC](https://codewiki.com/backend/trpc/)
- Importing server values into a client bundle.
  Why: A generated client imports `appRouter` rather than `type AppRouter`, which can pull database modules, secrets, or Node-only code toward the browser build. Export the router type from a server-safe boundary and use `import type` in the client. Inspect the production bundle and keep runtime client configuration separate from server initialization.
  Source: [tRPC](https://codewiki.com/backend/trpc/)
- Do not assume batching gives transaction semantics.
  Why: Two mutations sent by `httpBatchLink` can succeed or fail independently, and a retry may replay work whose earlier result was lost. Put operations that must commit together behind one application transaction. For retryable writes, define idempotency at the business boundary and test duplicate delivery and partial failure.
  Source: [tRPC](https://codewiki.com/backend/trpc/)
- Deploying a breaking router change as if types were live negotiation.
  Why: Already-built clients retain their old assumptions even after the shared source type changes. Renaming a procedure or narrowing its input can break them at runtime. Make additive changes first, observe old-client traffic, and remove compatibility only after the supported deployment window. Use contract tests that run old serialized requests against the new server.
  Source: [tRPC](https://codewiki.com/backend/trpc/)
- A nonthrowing return from `try await session.data(for:)` only says that URL loading delivered a response.
  Why: A 404 or 500 can still return `Data`, and its error body might happen to decode into an overly permissive model.
  Source: [URLSession](https://codewiki.com/backend/urlsession/)
- `URL(string: base + "?q=" + input)!` mixes path, query, and encoding.
  Why: Slashes, spaces, `&`, Unicode, or invalid configuration can change the target, while tokens can leak through URL logs.
  Source: [URLSession](https://codewiki.com/backend/urlsession/)
- One `URLSession` per request fragments cookies, caching, connection reuse, metrics, and delegate lifetimes.
  Why: If a session retains a delegate and never becomes invalid, a short-lived wrapper can also leave a long-lived reference behind.
  Source: [URLSession](https://codewiki.com/backend/urlsession/)
- A fixed loop that retries every `URLError`, 429, and 5xx can create an order or charge more than once.
  Why: Cancellation and timeout say the client lacks a definite result; neither proves that the server didn't commit.
  Source: [URLSession](https://codewiki.com/backend/urlsession/)
- Do not assume this is safe: `try?` turns a missing field, wrong type, or malformed JSON into the same `nil`.
  Why: Printing complete headers and bodies to make up for the missing diagnosis then exposes tokens and personal data.
  Source: [URLSession](https://codewiki.com/backend/urlsession/)
- Calling `URLSession.shared.download` inside a `Task` doesn't make the transfer survive system termination of the app.
  Why: Conversely, a background session is a poor home for short JSON calls because it doesn't support data tasks.
  Source: [URLSession](https://codewiki.com/backend/urlsession/)
- "WSGI can handle only one request at a time" confuses the application call model with the server concurrency model.
  Why: Several processes or threads may call one application object at once, so process globals may be modified concurrently or exist as separate copies in different processes.
  Source: [WSGI](https://codewiki.com/backend/wsgi/)
- Generated code often returns `["ok"]` or makes a generator `yield` a string.
  Why: Python's ability to iterate those objects doesn't make them valid WSGI; response body items must be `bytes`.
  Source: [WSGI](https://codewiki.com/backend/wsgi/)
- Do not assume this is safe: calling `read()` without an argument on `wsgi.input` may wait for the client to finish sending or load an attacker-controlled body entirely into memory.
  Why: Trusting `CONTENT_LENGTH` without an application limit also leaves resource use uncontrolled.
  Source: [WSGI](https://codewiki.com/backend/wsgi/)
- Middleware that logs or modifies a response may call `list(result)`, buffering the whole response, and forget to call the downstream result's `close()`.
  Why: Another common bug defines a wrapper with only two parameters, so an exception path that passes `exc_info` fails.
  Source: [WSGI](https://codewiki.com/backend/wsgi/)
- `HTTP_X_USER`, `HTTP_X_FORWARDED_FOR`, and similar keys are only WSGI representations of request headers.
  Why: Treating them as an authenticated identity or true source address crosses a trust boundary when a public client can supply them directly.
  Source: [WSGI](https://codewiki.com/backend/wsgi/)
- Do not assume this is safe: an application that fails after part of the body has been sent can't reliably change the status to `500 Internal Server Error`.
  Why: An error handler that calls `start_response()` again without `exc_info` also violates the repeated-call rule.
  Source: [WSGI](https://codewiki.com/backend/wsgi/)
- Generated ASGI handlers often call a synchronous ORM, `time.sleep()`, a file API, or a blocking HTTP client directly from a coroutine.
  Why: During that call, the event loop thread cannot run other work on the same loop.
  Source: [WSGI and ASGI](https://codewiki.com/backend/wsgi-asgi/)
- Do not assume this is safe: wSGI's `wsgi.input` is a stream that middleware does not automatically replay for the inner application.
  Why: An ASGI body may also span several `http.request` events. Ignoring stream ownership or calling `receive()` only once leaves later code with empty or truncated data.
  Source: [WSGI and ASGI](https://codewiki.com/backend/wsgi-asgi/)
- ASGI uses a list of byte pairs and preserves repeated response headers.
  Why: Middleware that runs `dict(headers)` overwrites same-named fields such as multiple `set-cookie` entries. Mixing WSGI `str` headers with ASGI `bytes` headers also violates the interface.
  Source: [WSGI and ASGI](https://codewiki.com/backend/wsgi-asgi/)
- WSGI middleware may yield nonempty bytes before `start_response()` or forget to forward the response iterator's `close()`.
  Why: ASGI middleware may send `http.response.start` twice, omit the final `more_body: False`, or swallow a disconnect failure.
  Source: [WSGI and ASGI](https://codewiki.com/backend/wsgi-asgi/)
- A WSGI-to-ASGI adapter can mount a synchronous HTTP application behind an ASGI server, but it cannot add WebSockets, async request streaming, or nonblocking dependencies.
  Why: A reverse adapter cannot compress a long-lived connection into one synchronous WSGI HTTP call without losing semantics.
  Source: [WSGI and ASGI](https://codewiki.com/backend/wsgi-asgi/)
- Creating an asynchronous connection pool during module import can fork the resource into several workers or use it outside the event loop that created it.
  Why: Creating a client for every request has the opposite problem: it discards connection reuse and multiplies setup work.
  Source: [WSGI and ASGI](https://codewiki.com/backend/wsgi-asgi/)
