# PocketBase Data Normalization Pitfalls ## JSON fields come back as strings PocketBase's `json` field type does NOT guarantee parsed JSON arrays on read. The SDK may return JSON fields as **serialized strings** instead of parsed arrays/objects. Always normalize after fetching: ```typescript const records = await pb.collection('repairOrders').getList(1, 200, { ... }); const normalized = records.items.map((item: any) => { let services = item.services || []; if (typeof services === 'string' && services.trim()) { try { services = JSON.parse(services); } catch { services = []; } } if (!Array.isArray(services)) services = []; return { ...item, services }; }); ``` **Symptom:** `e.reduce is not a function` or `e.map is not a function` on fields you expected to be arrays. **Also affects:** edit modals that pre-populate from fetched records — apply the same normalization before `setState()`. ## Empty/malformed JSON strings Even when a JSON field has a value, it might be an empty string `""` or partially corrupted. JSON.parse on these throws `"Unexpected end of JSON input"`. Always wrap in try/catch: ```typescript try { parsed = JSON.parse(raw); } catch { parsed = []; } ``` ## Missing system fields (created, updated) Some PocketBase collections lack the standard `created`/`updated` auto-fields. This happens when collections were created via raw SQL or imported. **Symptom:** queries with `sort: '-created'` or `fields: '...,created'` return 400 errors. **Fix:** Use `sort: '-id'` (PocketBase IDs are time-sortable) and avoid requesting `created`/`updated` in the `fields` parameter. **Detection:** Test with `curl` first: ```bash curl -s "http://127.0.0.1:8091/api/collections/NAME/records?sort=-created&perPage=1" \ -H "Authorization: $TOKEN" ``` If it returns 400, the collection lacks `created`. ## Collection naming conventions PocketBase collection names are case-sensitive. `repairOrders` and `repair_orders` are different collections. When porting from one naming convention to another, test each collection name directly against the API. **Detection:** ```python for name in ['repairOrders', 'repair_orders', 'repairorders']: r = fetch(f'http://127.0.0.1:8091/api/collections/{name}/records?perPage=1') print(f"{name}: {'EXISTS' if r.status == 200 else 'MISSING'}") ``` ## PocketBase SDK error structure The `ClientResponseError` thrown by the PocketBase JS SDK has this shape: ``` error.message → top-level message ("Failed to create record.") error.status → HTTP status (400) error.response → full API response body: { data: { email: { message: "Value must be unique." } }, message: "Failed to create record.", status: 400 } ``` For field-level validation errors, access `error.response.data`. Do NOT assume `error.data` is the field errors — in some SDK versions `error.data` is an alias for `error.response` (the full response body), so field errors are at `error.response.data` or `error.data.data`. Simple reliable pattern: ```typescript const message = err instanceof Error ? err.message : 'Failed'; ``` The PocketBase SDK's `.message` already includes the user-facing error text.