abhigyanpatwari/GitNexus · error · GitNexusRcError
must be a string.
Error message
${source} must be a string. What it means
A manual WAL checkpoint hit an IO error and the retry driver exhausted its budget (CHECKPOINT_RETRY_ATTEMPTS = 3 attempts, backoff from BASE_DELAYS_MS plus jitter so concurrent analyzers do not retry in lockstep). The original IO error is rethrown un-wrapped so the CLI layer (analyze.ts) can classify the held-open cause (#2599) and render the --wal-checkpoint-threshold recovery hint. The run fails this checkpoint path rather than corrupting WAL state.
Solutions
- Close concurrent holders of the DB (stop `gitnexus serve`, IDE integrations, other analyzers) and rerun
- Free disk space — checkpoint IO errors often accompany a full volume
- Exclude the GitNexus storage directory from antivirus scanning
- Tune cadence via --wal-checkpoint-threshold (e.g. raise it to reduce rename churn, per the recovery hint analyze.ts renders)
Defensive patterns
Strategy: retry
Validate before calling
import fs from 'node:fs/promises';
// before a manual checkpoint: cheap preflight on the two common causes
await fs.access(dbPath); // surfaces ENOSPC path issues early
const stat = await fs.statfs(path.dirname(dbPath)).catch(() => null);
if (stat && stat.bavail * stat.bsize < 512 * 1024 * 1024) {
throw new Error('insufficient disk space for WAL checkpoint');
} Type guard
const isLbugIoError = (e: unknown): e is Error => e instanceof Error && /IO error/i.test(e.message);
Try / catch
try {
await checkpointWithRetry(driver);
} catch (e) {
if (isLbugIoError(e)) {
// retry budget (3 attempts, backoff+jitter) is exhausted; the error reaches here
// unwrapped so the held-open classifier in analyze.ts can name the cause —
// stop concurrent DB users, free disk, then re-run analyze
throw e;
}
throw e;
} Prevention
- Stop `gitnexus serve` / IDE extensions before running a full analyze on the same storage
- Keep free disk headroom above the WAL size before checkpoint-heavy phases
- AV-exclude the storage directory to stop IO errors during WAL rename/remove churn
When it happens
Trigger: CHECKPOINT wal; returns an IO error three times in a row — another process/reader holding the DB file open (the #2599 held-open cause), a full or failing disk, or AV interference on the WAL/sidecar files during the rename/remove churn of checkpointing.
Common situations: Concurrent `gitnexus serve` / IDE extension holding the DB while analyze tries to checkpoint; disk-full on CI; aggressive antivirus locking .wal/.shadow during rename; network storage dropping writes. Followed by the analyze-layer error with the recovery hint.
Related errors
- GitNexus: manual WAL checkpoint failed after retries
- LadybugDB checkpoint sidecar is missing for
- LadybugDB checkpoint sidecar is missing for
- GitNexus could not move the LadybugDB WAL sidecar at
- GitNexus could not move the LadybugDB WAL sidecar at
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-01).
Data as JSON: /api/errors/7aaee73a0bb7b6b6.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/cli/analyze-config.ts:220
case 'branch':
if (typeof value !== 'string') {
throw new GitNexusRcError(`${source} must be a string branch name.`);
}
return validateBranchName(value, source);
case 'path': {
if (typeof value !== 'string') {
throw new GitNexusRcError(`${source} must be a file or directory path.`);
}
const trimmed = value.trim();
if (!trimmed) {
throw new GitNexusRcError(`${source} must not be empty.`);
}
assertNoHiddenChars(trimmed, source);
return trimmed;
}
case 'string': {
if (typeof value !== 'string') {
throw new GitNexusRcError(`${source} must be a string.`);
}
const trimmed = value.trim();
if (!trimmed) {
throw new GitNexusRcError(`${source} must not be empty.`);
}
assertNoHiddenChars(trimmed, source);
// `name` flows into the generated AGENTS.md/CLAUDE.md as `**${name}**` and
// inside `gitnexus://repo/${name}/…` code spans, so a Markdown-significant
// character would break those spans or inject emphasis/links/HTML into
// agent-instruction content (#1996 tri-review P1). `_` is intentionally
// allowed (legitimate in repo names; intraword `_` is not emphasis).
// embeddingDevice (the other `string`-kind option) only ever holds a
// fixed device token, so this guard never rejects a valid value there.
if (/[`*[\]<>]/.test(trimmed)) {
throw new GitNexusRcError(
`${source} must not contain Markdown-significant characters (\` * [ ] < >).`,
);
}View on GitHub (pinned to ac9a4e9abd)