abhigyanpatwari/GitNexus · error

Write queries are not allowed via the HTTP API

Error message

Write queries are not allowed via the HTTP API

What it means

HTTP 403 from POST /api/query when the Cypher statement attempts a write and the read-only LadybugDB connection rejects it — the catch inspects the error with isReadOnlyDbError. The HTTP API deliberately opens withLbugDb in readOnly: true mode, so the endpoint is a query surface only; any CREATE/MERGE/DELETE/SET/REMOVE/DETACH DELETE/DROP-style clause surfaces as this 403.

Source

Thrown at gitnexus/src/server/api.ts:674

      res.status(400).json({
        error: '"params" must be a plain object with scalar values (string/number/boolean/null)',
      });
      return;
    }

    const entry = await resolveRepo(requestedRepo(req));
    if (!entry) {
      res.status(404).json({ error: 'Repository not found' });
      return;
    }
    const lbugPath = path.join(entry.storagePath, 'lbug');
    const result = await withLbugDb(lbugPath, () => executePrepared(cypher, queryParams ?? {}), {
      readOnly: true,
    });
    res.json({ result });
  } catch (err: any) {
    if (isReadOnlyDbError(err)) {
      res.status(403).json({ error: 'Write queries are not allowed via the HTTP API' });
      return;
    }
    res.status(500).json({ error: err.message || 'Query failed' });
  }
};

/**
 * Validate the optional `token` field of POST /api/analyze. Returns an
 * { status, error } to send, or null when the token is absent or valid.
 *
 * The token is a GitHub PAT: charset-restricted (blocks CRLF header
 * smuggling), length-bounded (1–256), and bound to github.com using the SAME
 * GITHUB_TOKEN_HOSTS allowlist + hostname parse as resolveGitCredential, so a
 * token the API accepts is exactly the one buildGitEnv will inject — and one
 * it rejects is never sent off github.com.
 *
 * Exported for unit tests (the route validation is otherwise only reachable
 * by booting the server).

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Rewrite the statement as read-only: MATCH/WITH/UNWIND/WHERE/RETURN only
  2. Perform any write/maintenance through the gitnexus CLI (which owns index mutation) rather than the HTTP API
  3. If a mutation genuinely belongs in the product, request/expect a dedicated authenticated admin endpoint — do not try to bypass the read-only flag
  4. Check nested CALL { ... } blocks for hidden writes — the read-only rejection applies to the whole transaction

Example fix

// before
body: JSON.stringify({ cypher: 'MATCH (n:Symbol) SET n.seen = true RETURN n' }) // 403

// after
body: JSON.stringify({ cypher: 'MATCH (n:Symbol) RETURN n.name LIMIT 25' }) // read-only is allowed
Defensive patterns

Strategy: validation

Validate before calling

// Reject write-shaped Cypher before it reaches the API.
const WRITE_CLAUSE = /\b(CREATE|MERGE|DELETE|DETACH|SET|REMOVE|DROP|LOAD\\s+CSV|FOREACH)\b/i;
function assertReadOnlyCypher(cypher: string): void {
  // strip string literals so keywords inside quotes don't false-positive
  const stripped = cypher.replace(/'[^']*'|\"[^\"]*\"/g, '');
  if (WRITE_CLAUSE.test(stripped)) throw new Error('HTTP query API is read-only — remove write clauses');
}

Try / catch

const res = await postQuery(cypher);
if (res.status === 403 && /not allowed/.test((await res.json()).error)) {
  throw new Error('this query writes — use the gitnexus CLI for index mutations');
}

Prevention

When it happens

Trigger: MATCH (n) MERGE (n:X) RETURN n; MATCH (n) DELETE n; SET/REMOVE property writes; CALL of a subquery containing writes; maintaining Cypher that worked against a writable Neo4j and reusing it verbatim against the HTTP API.

Common situations: Trying to clean up or annotate graph nodes through the serve API instead of the CLI; porting admin Cypher scripts to the web client; experiments meant for a local writable console pasted into /api/query; misunderstandings where users expect the API to mutate the index.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/acdc04586f66f609. Report an issue: GitHub.