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

  1. Stop the autopilot process (the named signal tells you which), then re-run /sync-gbrain.
  2. If drift is perpetual (every sync reports it), align the registered path with the actual path permanently — re-add at the canonical location once.
  3. Verify detectAutopilot isn't reporting a stale signal (e.g. a leftover lockfile); clean it if so.
  4. 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

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


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/39e5bb85819d33be. Report an issue: GitHub.