Skip to content

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.js was brittle; it hardcoded an expectation for snake_case input (specifically macros_g.protein) coming from the LLM. However, PendingMealCard and other UI flows were already passing normalized camelCase data (flat structure), causing macros_g to be undefined.

2. Approach

  • Fix: Updated frontend/src/services/ApiMealService.js to use parseAndNormalizeMeal utility.
  • Rationale: This ensures addMeal is 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 parseAndNormalizeMeal function is fully unit tested and covers the camelCase input scenario.
  • Verification: Verified that existing tests pass (bun run test). mealParser.test.js explicitly confirms support for the input format that was failing.

4. Execution Plan

  • Identify root cause (mismatch between ApiMealService expectation and actual pendingMeal data).
  • Update ApiMealService.js to use parseAndNormalizeMeal.
  • Verify mealParser.test.js covers 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:

  1. Adopt TypeScript (High Priority):

    • Why: A static type system would have flagged the mismatch between the PendingMeal interface passed by the UI and the input expected by ApiMealService at compile time.
    • Action: Begin incremental migration of services/ and hooks/ to .ts/.tsx.
  2. Centralize Mock Data Factories:

    • Why: The bug slipped through because ApiMealService tests likely used "Happy Path" mocks that didn't reflect the actual data output of the parser.
    • Action: Create a shared tests/factories module. 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.
  3. Integration Testing for Hooks:

    • Why: Unit tests isolated the Service from the Component.
    • Action: Write an integration test for useMeals that simulates the full flow: Parser -> Hook -> Service. This ensures the data passing through the pipeline remains compatible at every stage.
  4. 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 parseAndNormalizeMeal utility as a gatekeeper.