abhigyanpatwari/GitNexus · error
GITNEXUS_MCP_READ_ONLY must be 0 or 1.
Error message
GITNEXUS_MCP_READ_ONLY must be 0 or 1.
What it means
Thrown by resolveMcpReadOnlyMode when the GITNEXUS_MCP_READ_ONLY environment variable is set to anything other than the exact recognized values. After trimming, only undefined (unset), '' (empty), '0' (read-write) and '1' (read-only) are accepted. The check is strict because this variable turns the MCP server into a hardened read-only surface, so loose truthiness parsing ('true', 'yes', 'on') is intentionally rejected.
Source
Thrown at gitnexus/src/mcp/read-only-policy.ts:27
'detect_changes',
'check',
'impact',
'explain',
'pdg_query',
'route_map',
'tool_map',
'shape_check',
'api_impact',
'trace',
]);
const MCP_READ_ONLY_ALIASES = new Set(['search', 'explore', 'overview']);
export function resolveMcpReadOnlyMode(env: NodeJS.ProcessEnv = process.env): boolean {
const value = env.GITNEXUS_MCP_READ_ONLY?.trim();
if (value === undefined || value === '' || value === '0') return false;
if (value === '1') return true;
throw new Error('GITNEXUS_MCP_READ_ONLY must be 0 or 1.');
}
export function assertMcpReadOnlyToolCall(
toolName: string,
args: Record<string, unknown> | undefined,
readOnly: boolean,
): void {
if (!readOnly) return;
if (!MCP_READ_ONLY_TOOLS.has(toolName) && !MCP_READ_ONLY_ALIASES.has(toolName)) {
throw new Error(`Tool "${toolName}" is not available in GitNexus MCP read-only mode.`);
}
if (typeof args?.repo === 'string' && args.repo.trim().startsWith('@')) {
throw new Error('Group routing is not available in GitNexus MCP read-only mode.');
}
// crossDepth/subgroup only do anything on the @group path rejected above,
// but rejecting them here keeps the advertised schema and the dispatch
// contract in agreement.
for (const groupOnlyArg of ['crossDepth', 'subgroup']) {View on GitHub (pinned to aac7515d2a)
Solutions
- Set the variable to exactly 1 (enable read-only) or 0 (disable), e.g. GITNEXUS_MCP_READ_ONLY=1 npx gitnexus mcp.
- Unset the variable entirely if you want read-write mode — undefined and empty both mean off.
- Search the environment and .env files for the variable and correct every occurrence; do not use true/false/yes/no spellings.
Example fix
# before export GITNEXUS_MCP_READ_ONLY=true # after export GITNEXUS_MCP_READ_ONLY=1
Defensive patterns
Strategy: validation
Validate before calling
const raw = process.env.GITNEXUS_MCP_READ_ONLY;
const readOnly = raw === undefined || raw.trim() === '' || raw.trim() === '0' ? false : raw.trim() === '1';
if (readOnly === undefined && !(raw!.trim() === '1')) {
throw new Error(`GITNEXUS_MCP_READ_ONLY has invalid value: ${JSON.stringify(raw)}`);
} Type guard
const isValidReadOnlyEnv = (v: string | undefined): boolean => v === undefined || ['', '0', '1'].includes(v.trim());
Try / catch
try {
spawnGitnexusMcp();
} catch (e) {
if (e instanceof Error && e.message.includes('GITNEXUS_MCP_READ_ONLY')) {
// config error: fix the env value and restart; retrying unchanged cannot help
}
throw e;
} Prevention
- Standardize on 0/1 spellings in all .env files and deployment manifests; lint for =true/=yes.
- Add a startup env validation step to deployment scripts before launching the MCP server.
- Document the variable as boolean-flag style (0/1) wherever it is referenced.
When it happens
Trigger: Starting the GitNexus MCP server with GITNEXUS_MCP_READ_ONLY set to 'true', 'yes', 'on', '2', 'TRUE', 'read', or any other string; the error surfaces as soon as the policy is resolved at startup or on first tool/resource dispatch.
Common situations: Operators habitually write GITNEXUS_MCP_READ_ONLY=true (shell/COMMON convention) instead of 1. A .env loader keeps a quoted or padded value. Upgrading from a version that ignored the variable to one that enforces it.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
Related errors
- ${source} must be a positive integer.
- ${allowedRaw.key} must not be blank.
- ${defaultRaw.key} must not be blank.
- ${name} must be a positive integer, got "${raw}"
- ${name} must be a non-negative integer, got "${raw}"
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/d85e441a0b2aa27b.
Report an issue: GitHub.