Troubleshooting
Local Docker / Supabase
Colima: disable Supabase analytics
On Colima (macOS Docker alternative), the Supabase vector (log analytics) container fails to start because it cannot bind-mount the Docker socket. Disable it in app/supabase/config.toml:
[analytics]
enabled = false
Without this, supabase start hangs or errors on Colima environments.
postgres:18 image - wrong volume mount path
If you use a postgres:18 container (for example, for the PowerSync bucket-storage database), mount the data volume at /var/lib/postgresql, not /var/lib/postgresql/data:
volumes:
- pg_storage_data:/var/lib/postgresql
Mounting at /var/lib/postgresql/data causes the container to fail on startup because postgres:18 changed the default data directory.
PowerSync client
No INSERT ... ON CONFLICT on PowerSync tables
PowerSync client tables are SQLite views backed by INSTEAD OF triggers. They accept plain INSERT, UPDATE, and DELETE statements, but not INSERT ... ON CONFLICT (upsert syntax).
Upsert logic must be done manually - check for row existence first, then INSERT or UPDATE:
// from app/services/powersync/mutations.ts
async function upsertRow(table, id, row) {
await db.writeTransaction(async (tx) => {
const existing = await tx.getOptional(`SELECT id FROM ${table} WHERE id = ?`, [id])
if (existing) {
await tx.execute(`UPDATE ${table} SET ... WHERE id = ?`, [...values, id])
}
else {
await tx.execute(`INSERT INTO ${table} (id, ...) VALUES (?, ...)`, [id, ...values])
}
})
}
See app/services/powersync/mutations.ts for the full implementation.
Every synced table must have an id PK
PowerSync requires an id primary key on every synced table. For user_settings, the id column holds the user's Supabase uid. This is how the table satisfies the requirement while having exactly one row per user.
Synchronous auth gate
The route guard in app/app/middleware/auth.global.ts is synchronous - it reads the persisted Supabase session from localStorage (hasPersistedSession(), app/app/composables/useAuthSession.ts) with no network call, so it works offline. There is no auth cookie.
supabase-js persists the session to localStorage itself as part of sign-in, so by the time login code navigates, the gate already passes. The PowerSync plugin separately watches the reactive uid from useSupabaseAuth() and connects/disconnects PowerSync as the session resolves - navigation does not wait for it.
If you move login flow logic around, navigate only after the sign-in promise resolves (session persisted) - otherwise the guard will redirect back to /login.