Product Search Went Blank — Fixing an API Response Structure Mismatch
Real experience: 2026-03-21, debugging an ERP admin panel
What Happened
Clicking the "Product Search" button in our ERP admin panel caused the entire page to go white. The console showed Cannot read properties of undefined (reading 'map').
Quick assessment:
- Build was passing fine
- Other pages worked normally
- The crash happened the instant the search dialog opened
Finding the Root Cause
First, I checked the SearchDialog component. It calls .map() on the API response to render a product list, assuming that response.data is an array.
Then I hit the actual API endpoint and looked at the raw response:
{
"code": 1,
"data": {
"list": [...],
"total": 42
}
}
Here's the catch. The ERP's API client (request()) detects code === 1 as "success" and automatically unwraps the data field before returning it. So what the caller actually receives is:
{
"list": [...],
"total": 42
}
SearchDialog tries to access response.data, but the received object has no data property. Hence undefined.map() — crash.
The Fix
Changing the API client's unwrapping behavior was too risky — no telling what else it might break. Instead, I added a getProducts() function to erpCompat.ts, a compatibility layer that normalizes the response:
export async function getProducts(params: ProductSearchParams) {
const result = await request('/erp/products', params);
// Normalize when API returns unwrapped { list, total }
if (result && Array.isArray(result.list)) {
return {
data: result.list,
total: result.total ?? 0,
};
}
// Already in { data: [...] } format — pass through
return result;
}
SearchDialog just calls getProducts(). If the API's internal behavior changes, normalization is handled in one place.
Lessons Learned
API response unwrapping is not "transparent." If you don't realize that request() is silently stripping the data wrapper, the types at the call site will be "shifted" from reality. Even with TypeScript, this kind of bug lurks silently wherever types fall back to any.
Takeaways:
- Document the API client's unwrapping behavior (or express it through types)
- Always check actual response values (don't blindly trust type inference)
- Normalize via a compatibility layer (don't let components touch raw API responses directly)
This bug only surfaced after deployment, but thanks to the compatibility layer design, the fix was minimal. A thin wrapper function really does pay for itself.
Top comments (0)