mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(sync): crash-safe renames loop — record per-file failures instead of throwing (#2402)
The renames loop reimports each renamed file via importFile() but, unlike the deletes and adds/mods loops, does not wrap the call. importFile() still throws on content sanity-block, duplicate-slug, and missing-link endpoints, so a single malformed renamed file throws uncaught and crashes the whole sync mid-run — freezing the checkpoint and defeating --skip-failed. A 'skipped' result carrying an error was also silently dropped (never recorded to failedFiles). This wraps the reimport in try/catch and records both the throw and the skipped-with-error case to failedFiles, matching the existing deletes/adds loop pattern. Surfaced in the wild by a tree-wide rename (a shared/ -> system/ vault migration, ~10.8k renames) where one malformed-YAML renamed file crashed the entire incremental sync at rename ~4900/10857. Co-authored-by: jaxlewis-swift <jaxlewis@swiftsolutions.ai>
This commit is contained in:
co-authored by
jaxlewis-swift
parent
78bc2fef09
commit
74bc8f8cd1
+16
-3
@@ -2306,11 +2306,24 @@ async function performSyncInner(engine: BrainEngine, opts: SyncOpts): Promise<Sy
|
||||
} catch {
|
||||
// Slug doesn't exist or collision, treat as add
|
||||
}
|
||||
// Reimport at new path (picks up content changes)
|
||||
// Reimport at new path (picks up content changes). Wrapped to match the
|
||||
// deletes/adds loops: a malformed renamed file is recorded to failedFiles
|
||||
// and skipped, NOT thrown uncaught. importFile still throws on content
|
||||
// sanity-block, duplicate-slug, and missing-link endpoints; an uncaught
|
||||
// throw here crashes the whole sync mid-run and freezes the checkpoint,
|
||||
// defeating --skip-failed. A `skipped` result carrying an error is also
|
||||
// captured so the failure is recorded rather than silently dropped.
|
||||
const filePath = join(repoPath, to);
|
||||
if (existsSync(filePath)) {
|
||||
const result = await importFile(engine, filePath, to, { noEmbed, sourceId: opts.sourceId, activePack: syncActivePack });
|
||||
if (result.status === 'imported') chunksCreated += result.chunks;
|
||||
try {
|
||||
const result = await importFile(engine, filePath, to, { noEmbed, sourceId: opts.sourceId, activePack: syncActivePack });
|
||||
if (result.status === 'imported') chunksCreated += result.chunks;
|
||||
else if (result.status === 'skipped' && (result as { error?: string }).error) {
|
||||
failedFiles.push({ path: to, error: String((result as { error?: string }).error) });
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
failedFiles.push({ path: to, error: e instanceof Error ? e.message : String(e) });
|
||||
}
|
||||
}
|
||||
pagesAffected.push(newSlug);
|
||||
await markCompleted(to);
|
||||
|
||||
Reference in New Issue
Block a user