garrytan/gstack · error · Error
refusing drift re-register of ${id}: autopilot active (${ap.
Error message
refusing drift re-register of ${id}: autopilot active (${ap.signal}). Stop autopilot, then re-run /sync-gbrain. What it means
Thrown by ensureSourceRegistered() in the drift branch when a source is registered at a different path than requested AND detectAutopilot reports autopilot active. Re-registering a drifted source requires a destructive remove (which deletes pages/chunks/embeddings) followed by re-add; running that while autopilot is indexing would corrupt the in-progress rebuild. The refusal is fatal by design — returning changed=false would silently hide the drift. The message names the id and the autopilot signal so the operator knows what to stop.
Source
Thrown at lib/gbrain-sources.ts:217
// as "source registration failed" and aborts the whole /sync-gbrain code
// stage for any source that has drifted to a new path. This matches the
// flag the orchestrator's own safeSourcesRemove() already passes.
if (state.status === "drift") {
// Loud drift observability: if this line shows up on every sync for some
// environment, drift is perpetual there and the reindex-in-place design
// from #1985 should be promoted (drop+rebuild re-embeds the full index).
console.error(
`[gbrain-sources] drift: ${id} registered at ${state.registered_path} -> re-registering at ${path}`,
);
// #1734: this remove deletes the source's pages/chunks/embeddings, so it
// runs only behind the same data-loss guards as the orchestrator's
// safeSourcesRemove(). A refusal is FATAL here (not best-effort): without
// the remove the add cannot proceed, and returning changed=false would
// silently hide the drifted registration.
const ap = detectAutopilot(env ?? process.env, options.autopilotProbe ?? {});
if (ap.active) {
throw new Error(
`refusing drift re-register of ${id}: autopilot active (${ap.signal}). ` +
`Stop autopilot, then re-run /sync-gbrain.`,
);
}
const decision = decideSourceRemove(id, env ?? process.env, options.removeDecision ?? {});
if (!decision.allow) {
throw new Error(`refusing drift re-register of ${id}: ${decision.reason}`);
}
const rm = spawnSync(
"gbrain",
["sources", "remove", id, "--yes", "--confirm-destructive", ...decision.extraArgs],
{
encoding: "utf-8",
timeout: 30_000,
env,
shell: NEEDS_SHELL_ON_WINDOWS, // #1731: gbrain is a .cmd shim on Windows
},View on GitHub (pinned to 94993f7401)
Solutions
- Stop the autopilot process (the named signal tells you which), then re-run /sync-gbrain.
- If drift is perpetual (every sync reports it), align the registered path with the actual path permanently — re-add at the canonical location once.
- Verify detectAutopilot isn't reporting a stale signal (e.g. a leftover lockfile); clean it if so.
- As a last resort, manually remove the drifted source via gbrain CLI after confirming autopilot is stopped.
Defensive patterns
Strategy: validation
Validate before calling
import { detectAutopilot } from './gbrain-guards';
function assertAutopilotIdle(env: NodeJS.ProcessEnv = process.env): void {
const ap = detectAutopilot(env, {});
if (ap.active) throw new Error(`Stop autopilot (${ap.signal}) before re-registering sources.`);
} Try / catch
try {
return await ensureSourceRegistered(id, path, options);
} catch (e) {
if (e instanceof Error && e.message.startsWith('refusing drift re-register') && /autopilot active/.test(e.message)) {
// Stop autopilot, then re-run /sync-gbrain
throw new Error('Autopilot is running. Stop it, then re-run /sync-gbrain.');
}
throw e;
} Prevention
- Always stop autopilot before re-running /sync-gbrain on a moved repository.
- Resolve perpetual drift by re-adding the source at its canonical path once.
- Clean up stale autopilot lockfiles/signal files before sync.
- Run sync from a stable absolute path to avoid drift on CI runners.
When it happens
Trigger: probeSource returns status=match but the realpath-normalized path differs from the requested path (drift), and detectAutopilot(env).active is true. The function then throws before attempting the remove+add, instructing the operator to stop autopilot first.
Common situations: Repository moved on disk so the source path changed while gbrain still tracks the old location, and autopilot is mid-reindex; a CI machine clones to a temp dir each run causing perpetual drift; symlink re-resolved to a different absolute path; autopilot left running from a previous session.
Related errors
- gbrain sources list returned no JSON
- refusing drift re-register of ${id}: ${decision.reason}
- gbrain CLI not on PATH
- gbrain not configured (run /setup-gbrain)
- gbrain sources list returned non-JSON output: ${(err as Erro
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/39e5bb85819d33be.
Report an issue: GitHub.