Bug Description
When running gbrain autopilot or gbrain dream in a multi-source brain (e.g. multiple sources registered via gbrain sources add), the sync phase fails with a foreign key constraint violation:
insert or update on table "pages" violates foreign key constraint "pages_source_id_fkey"
This causes all file imports in the cycle to fail silently, leaving the brain stale.
Root Cause
In src/core/cycle.ts, runPhaseSync() resolves the source ID by matching the autopilot's --repo path against sources.local_path:
// src/core/cycle.ts:558
const sourceId = await resolveSourceForDir(engine, brainDir);
resolveSourceForDir() does an exact match:
SELECT id FROM sources WHERE local_path = $1 LIMIT 1
When --repo /home/ubuntu/brain is passed but all sources have subdirectory paths like:
logseq → /home/ubuntu/onedrive/OneSyncFiles/
wiki → /home/ubuntu/brain/wiki/
obsidian → /home/ubuntu/onedrive/my_obsidian/
No source matches, so sourceId resolves to undefined. The importFile() then falls back to the schema DEFAULT for source_id, which is 'default':
-- pages.source_id has default 'default'
But no row exists in sources with id = 'default', triggering the FK constraint violation on every insert.
Reproduction Steps
-
Register multiple sources with different local_path values:
gbrain sources add wiki --path /home/ubuntu/brain/wiki
gbrain sources add obsidian --path /home/ubuntu/onedrive/my_obsidian
gbrain sources add logseq --path /home/ubuntu/onedrive/OneSyncFiles
-
Start autopilot with a parent directory that doesn't match any source:
gbrain autopilot --repo /home/ubuntu/brain --interval 900
-
Observe sync phase: all files fail with pages_source_id_fkey violation.
Environment
- gbrain v0.35.1.0
- Engine: postgres (Supabase)
- Sources: 4 (logseq, wiki, obsidian, books)
- OS: Linux arm64
Proposed Fix
Modify runPhaseSync() to enumerate all registered sources from the database and sync each one individually, rather than relying on a single brainDir match:
// Instead of resolving one source for brainDir:
const sourceId = await resolveSourceForDir(engine, brainDir);
// Enumerate all sources and sync each:
const sources = await engine.executeRaw<{ id: string; local_path: string }>(
`SELECT id, local_path FROM sources WHERE local_path IS NOT NULL AND local_path != ''`,
);
for (const src of sources) {
const result = await performSync(engine, {
repoPath: src.local_path,
sourceId: src.id,
// ...
});
}
This ensures each source is synced with its correct source_id, avoiding the FK constraint error. The fallback path is preserved for brains with no registered sources.
I can submit a PR with the full patch if this approach is acceptable.
Workaround
Manually sync each source individually:
gbrain sync --source logseq
gbrain sync --source wiki
gbrain sync --source obsidian
Bug Description
When running
gbrain autopilotorgbrain dreamin a multi-source brain (e.g. multiple sources registered viagbrain sources add), the sync phase fails with a foreign key constraint violation:This causes all file imports in the cycle to fail silently, leaving the brain stale.
Root Cause
In
src/core/cycle.ts,runPhaseSync()resolves the source ID by matching the autopilot's--repopath againstsources.local_path:resolveSourceForDir()does an exact match:When
--repo /home/ubuntu/brainis passed but all sources have subdirectory paths like:logseq→/home/ubuntu/onedrive/OneSyncFiles/wiki→/home/ubuntu/brain/wiki/obsidian→/home/ubuntu/onedrive/my_obsidian/No source matches, so
sourceIdresolves toundefined. TheimportFile()then falls back to the schema DEFAULT forsource_id, which is'default':-- pages.source_id has default 'default'But no row exists in
sourceswithid = 'default', triggering the FK constraint violation on every insert.Reproduction Steps
Register multiple sources with different
local_pathvalues:Start autopilot with a parent directory that doesn't match any source:
Observe sync phase: all files fail with
pages_source_id_fkeyviolation.Environment
Proposed Fix
Modify
runPhaseSync()to enumerate all registered sources from the database and sync each one individually, rather than relying on a singlebrainDirmatch:This ensures each source is synced with its correct
source_id, avoiding the FK constraint error. The fallback path is preserved for brains with no registered sources.I can submit a PR with the full patch if this approach is acceptable.
Workaround
Manually sync each source individually: