3.2 KiB
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:
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:
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:
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:
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:
const message = err instanceof Error ? err.message : 'Failed';
The PocketBase SDK's .message already includes the user-facing error text.