# 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.
