2026-01-04: Fix API Meal Service TypeError
Task Metadata
Date: 2026-01-04
Status: Complete
1. Context
- Goal: Fix a
TypeError: Cannot read properties of undefined (reading 'protein')when adding a meal via the Dashboard. - Trigger: User reported the error via TanStack Query DevTools logs.
- Root Cause:
ApiMealService.jswas brittle; it hardcoded an expectation forsnake_caseinput (specificallymacros_g.protein) coming from the LLM. However,PendingMealCardand other UI flows were already passing normalizedcamelCasedata (flat structure), causingmacros_gto be undefined.
2. Approach
- Fix: Updated
frontend/src/services/ApiMealService.jsto useparseAndNormalizeMealutility. - Rationale: This ensures
addMealis resilient to any input format (Legacy Snake, Legacy Pascal, or New Camel), leveraging the "Centralized Normalization" pattern established in the previous data format uplift.
3. Impact Analysis
- Files Modified:
frontend/src/services/ApiMealService.js - Risk: Low. The
parseAndNormalizeMealfunction is fully unit tested and covers thecamelCaseinput scenario. - Verification: Verified that existing tests pass (
bun run test).mealParser.test.jsexplicitly confirms support for the input format that was failing.
4. Execution Plan
- Identify root cause (mismatch between
ApiMealServiceexpectation and actualpendingMealdata). - Update
ApiMealService.jsto useparseAndNormalizeMeal. - Verify
mealParser.test.jscovers the scenario. - Run frontend tests.
5. Recommendations for Future Prevention
To prevent similar data shape mismatches (where a service expects format A but the UI sends format B) from recurring, we should prioritize the following:
-
Adopt TypeScript (High Priority):
- Why: A static type system would have flagged the mismatch between the
PendingMealinterface passed by the UI and the input expected byApiMealServiceat compile time. - Action: Begin incremental migration of
services/andhooks/to.ts/.tsx.
- Why: A static type system would have flagged the mismatch between the
-
Centralize Mock Data Factories:
- Why: The bug slipped through because
ApiMealServicetests likely used "Happy Path" mocks that didn't reflect the actual data output of the parser. - Action: Create a shared
tests/factoriesmodule. When the data shape changes (e.g., the recent Casing Uplift), updating the single factory will break all dependent tests, alerting us to the disconnect immediately.
- Why: The bug slipped through because
-
Integration Testing for Hooks:
- Why: Unit tests isolated the Service from the Component.
- Action: Write an integration test for
useMealsthat simulates the full flow:Parser -> Hook -> Service. This ensures the data passing through the pipeline remains compatible at every stage.
-
Defensive Service Layers (Pattern Confirmed):
- Why: We cannot always guarantee the shape of data coming from loose, untyped JavaScript sources (or LLMs).
- Action: Continue the pattern established here: Services should explicitly normalize/validate their inputs at the entry point rather than assuming a specific shape. Use the
parseAndNormalizeMealutility as a gatekeeper.