garrytan/gstack · error · Error
gbrain sources add ${id} failed: ${add.stderr || add.stdout
Error message
gbrain sources add ${id} failed: ${add.stderr || add.stdout || `exit ${add.status}`} What it means
Thrown after spawnSync('gbrain', ['sources','add',id,'--path',path,(--federated)]) returns non-zero at the end of drift re-registration (or a fresh registration). Like 321 it surfaces the child's stderr/stdout/exit code. The remove already succeeded, so a failure here leaves the source unregistered.
Source
Thrown at lib/gbrain-sources.ts:252
shell: NEEDS_SHELL_ON_WINDOWS, // #1731: gbrain is a .cmd shim on Windows
},
);
if (rm.status !== 0) {
throw new Error(`gbrain sources remove ${id} failed: ${rm.stderr || rm.stdout || `exit ${rm.status}`}`);
}
}
// Add.
const addArgs = ["sources", "add", id, "--path", path];
if (federated) addArgs.push("--federated");
const add = spawnSync("gbrain", addArgs, {
encoding: "utf-8",
timeout: 30_000,
env,
shell: NEEDS_SHELL_ON_WINDOWS, // #1731: gbrain is a .cmd shim on Windows
});
if (add.status !== 0) {
throw new Error(`gbrain sources add ${id} failed: ${add.stderr || add.stdout || `exit ${add.status}`}`);
}
return {
changed: true,
state: { status: "match", registered_path: path },
};
}, "gbrain-sources");
}
/**
* Get page_count for a registered source. Returns null if source is absent or if
* page_count is missing/invalid in the JSON. Used by the verdict block + preamble
* variant selection.
*/
export function sourcePageCount(id: string, env?: NodeJS.ProcessEnv): number | null {
let stdout: string;
try {
stdout = execFileSync("gbrain", ["sources", "list", "--json"], {View on GitHub (pinned to 94993f7401)
Solutions
- Run `gbrain sources add <id> --path <path>` manually to see gbrain's own error.
- Confirm the path exists and is readable by the gbrain process before syncing.
- Ensure no concurrent sync is running (check for a gbrain lock file).
- Verify gbrain is on PATH and >= the version that supports your flags.
Example fix
// before
const add = spawnSync('gbrain', addArgs, { encoding:'utf-8', timeout:30_000, env, shell: NEEDS_SHELL_ON_WINDOWS });
if (add.status !== 0) throw new Error(`gbrain sources add ${id} failed: ${add.stderr || add.stdout || `exit ${add.status}`}`);
// after: validate path first, distinguish spawn/signal/exit
if (!fs.existsSync(path)) throw new Error(`cannot add ${id}: path does not exist: ${path}`);
const add = spawnSync('gbrain', addArgs, {...});
if (add.error) throw new Error(`gbrain add ${id} spawn failed: ${add.error.message}`);
if (add.signal) throw new Error(`gbrain add ${id} killed by ${add.signal}`);
if (add.status !== 0) throw new Error(`gbrain sources add ${id} failed: ${add.stderr || add.stdout || `exit ${add.status}`}`); Defensive patterns
Strategy: validation
Validate before calling
// Validate the path exists and gbrain is callable before triggering an add.
import fs from 'node:fs';
import { spawnSync } from 'node:child_process';
function preflightAdd(id: string, p: string, env = process.env): string | null {
if (!fs.existsSync(p)) return `path does not exist: ${p}`;
const v = spawnSync('gbrain', ['--version'], { encoding: 'utf-8', env, shell: process.platform === 'win32' });
if (v.status !== 0) return 'gbrain not on PATH or not executable';
return null;
}
const err = preflightAdd(id, path);
if (err) throw new Error(`preflight: ${err}`); Try / catch
try {
await ensureSourceRegistered(id, path);
} catch (e) {
if (/already registered|exists/i.test(String(e?.message ?? ''))) {
// idempotent — source is registered, treat as success
return;
}
throw e;
} Prevention
- Create the source directory before referencing it in a sync.
- Avoid concurrent /sync-gbrain runs on the same id (check for a lock).
- Confirm federated support matches your gbrain build before passing --federated.
- On Windows, ensure the .cmd shim path is correct.
When it happens
Trigger: The add spawnSync in ensureSourceRegistered() exits non-zero. Typical causes: path does not exist or is unreadable, the id already exists (race with another sync), --federated rejected by a non-federated gbrain, gbrain not on PATH, or a 30s timeout.
Common situations: Drift sync where the new path is a typo or not yet created; two /sync-gbrain runs racing on the same source; gbrain version that rejects --federated; Windows .cmd shim resolution failure; the path is a symlink whose target is gone.
Related errors
- gbrain sources remove ${id} failed: ${rm.stderr || rm.stdout
- git ${args.join(' ')} failed (exit ${result.status}): ${stde
- Unsupported file URL host: ${segment}. Use file:///<absolute
- gbrain sources list returned no JSON
- gbrain CLI not on PATH
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/86790974755e2650.
Report an issue: GitHub.