An endpoint that returns 404 when a collection is empty conflates two distinct states: "this endpoint does not exist" and "this collection has no items." Consumers must add special-case 404 handling to every list call, and any generic list component breaks for new users who have no data yet. Returning null instead of [] causes response.data.map is not a function in every consumer that did not add a null guard. iso-25010:2011 compatibility.interoperability requires a consistent response shape regardless of result count — consumers must be able to write one code path for all list responses.
Low because inconsistent empty collection handling causes consumer-side null reference errors and forces special-case code without enabling security exploits.
Always return an empty array with 200 status and consistent pagination metadata when a collection has no items:
// Before -- inconsistent empty handling:
if (results.length === 0) {
return Response.json({ message: 'No items found' }, { status: 404 })
}
// After -- consistent shape regardless of count:
return Response.json({
data: results, // [] when empty, same shape as non-empty
meta: { page: 1, limit: 20, total: 0, totalPages: 0 }
})
This lets consumers write response.data.map(...) once and have it work whether the array has 0 or 1000 items. The rule is simple: 404 means the endpoint does not exist, never that the collection is empty.
ID: api-design.developer-ergonomics.empty-collections
Severity: low
What to look for: Check what list endpoints return when the collection is empty. The correct behavior is to return an empty array [] (with 200 status and pagination metadata showing 0 total). Look for anti-patterns: returning null instead of [], returning 404 for empty collections (404 means the endpoint doesn't exist, not that the collection is empty), returning a different response shape for empty vs non-empty collections, or returning an error message like "No results found."
Pass criteria: Count all list endpoints that return collections. All list endpoints return an empty array [] with a 200 status code when the collection has no items. The response shape is identical to a non-empty response (same metadata fields, same envelope). Pagination metadata correctly shows total: 0.
Fail criteria: Empty collections return null instead of [], return 404, return a different response shape than non-empty collections, or return an error/message instead of an empty data array. Should not pass when any list endpoint returns 404 for an empty collection.
Skip (N/A) when: No list endpoints exist.
Detail on fail: Identify the issue (e.g., "GET /api/orders returns 404 when user has no orders. GET /api/comments returns { data: null } instead of { data: [] }. GET /api/notifications returns { message: 'No notifications' } instead of an empty array."). Max 500 chars.
Remediation: Always return [] for empty collections with 200 status:
// Before -- inconsistent empty handling:
if (results.length === 0) {
return Response.json({ message: 'No items found' }, { status: 404 })
}
// After -- consistent empty array:
return Response.json({
data: results, // [] when empty, same shape as non-empty
meta: { page: 1, limit: 20, total: 0, totalPages: 0 }
})
This lets consumers write one code path: response.data.map(...) works whether the array has 0 or 100 items.