Reported issues for repo2graph
Pod holds 16 of 26 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.
Back to repo2graph.
Most discussed
[P2] Update manifest.json checksums when redrawing graph.html in cmd_map
Problem
When running repo2graph map -o <out_dir> to re-render the visualization (human/graph.html) of an existing graph, cli.py:cmd_map loads graph.json, generates HTML, and calls write_html(..., html, ...).
However, unlike cmd_build and export.py, cmd_map never updates or re-registers the file checksum with agent/manifest.json.
# repo2graph/cli.py:644-648
html = render_html(graph_data, title=args.title)
write_html(html_path, html, minify=not…
[Read the thread](https://github.com/Srinivasan-78/repo2graph/issues/339) · 2026-09-22 · closed · 1 comment
### [P1] Make HTTP auto-build disabled by default
## Problem
A "read-only" MCP tool request can trigger a full local build, artifact write, parser execution, and Git interaction.
## Required changes
- Preserve auto-build for local stdio only if necessary.
- Make HTTP mode require explicit `--allow-auto-build` or equivalent.
- Add separate build authorization/capability if HTTP auto-build remains available.
- Return an actionable "index not available" response containing expected build instructions.
## Acceptance criteria
- Starting HTTP MCP…
[Read the thread](https://github.com/Srinivasan-78/repo2graph/issues/265) · 2026-09-21 · closed · 1 comment
### http_server: _read_body honours Content-Length only, leaving a chunked request body unread in the socket
**Problem.** `_read_body` (`repo2graph/http_server.py:277-285`) reads exactly what `Content-Length` declares:
```python
def _read_body(self) -> bytes:
try:
length = int(self.headers.get("Content-Length") or 0)
except ValueError:
raise AuthError("invalid Content-Length", status=400) from None
if length < 0 or length > MAX_BODY_BYTES:
raise AuthError(f"request body must be at most {MAX_BODY_BYTES} bytes", status=413)
return self.rfile.read(length) if…
[Read the thread](https://github.com/Srinivasan-78/repo2graph/issues/249) · 2026-09-19 · closed · 1 comment
### auth: a JWK with kty RSA but no n or e raises KeyError out of decode_jwt
**Problem.** `decode_jwt` (`repo2graph/auth.py:459-473`) checks the key type and the declared algorithm, then indexes the JWK's RSA parameters directly:
```python
key = jwks.key_for(str(kid))
if key.get("kty") != "RSA":
raise AuthError(f"unsupported key type {key.get('kty')!r}")
...
if not rsa_verify(
_int_from_b64url(str(key["n"])), # <- KeyError if absent
_int_from_b64url(str(key["e"])), # <- KeyError if absent
...
A key set advertising `{"kid": "k1", "kty":…
Read the thread · 2026-09-19 · closed · 1 comment
audit: sanitize_params recurses without a depth limit, so nested tool arguments raise RecursionError out of the unguarded _reject path
Problem. sanitize_value (repo2graph/audit.py:142-144) recurses into containers with no depth bound:
if isinstance(value, dict):
return {k: sanitize_value(str(k), v) for k, v in value.items()}
if isinstance(value, (list, tuple)):
return [sanitize_value(key, v) for v in value]
Verified:
$ python -c "
from repo2graph.audit import sanitize_params
d = {'a': 1}
for _ in range(3000): d = {'k': d}
sanitize_params(d)"
RecursionError: maximum recursion depth exceeded…
[Read the thread](https://github.com/Srinivasan-78/repo2graph/issues/234) · 2026-09-19 · closed · 1 comment
### http_server: a deeply nested JSON body raises RecursionError past `except ValueError`, killing the handler thread pre-auth
**Problem.** `do_POST` (`repo2graph/http_server.py:383-387`) parses the request body like this:
```python
try:
request = json.loads(raw.decode("utf8", "replace")) if raw else None
except ValueError:
self._send_json(400, _rpc_error(None, PARSE_ERROR, "invalid JSON"))
return
json.loads raises RecursionError — not a ValueError — on a deeply nested document, so that guard does not catch it. Verified:
$ python -c "
import json
for n in (2000, 20000):
try:…
[Read the thread](https://github.com/Srinivasan-78/repo2graph/issues/233) · 2026-09-19 · closed · 1 comment
### auth: a non-ASCII bearer credential raises TypeError out of authenticate(), killing the HTTP handler thread before auth resolves
**Problem.** `Authenticator.authenticate` (`repo2graph/auth.py:591`) compares the caller's credential against the static token with `hmac.compare_digest`:
```python
if self.config.token:
if hmac.compare_digest(credential, self.config.token):
return Identity(subject="bearer", mode="bearer")
hmac.compare_digest refuses str operands that are not ASCII-only — it raises TypeError, not a mismatch. The credential comes straight off the Authorization header, so any client that…
Read the thread · 2026-09-19 · closed · 1 comment
prod-igy: issue_comment trigger has no author_association gate, and branch names are interpolated into the bot comment
Problem (no author gate). prod-igy.yml fires the privileged triage job on issue_comment:
(github.event_name == 'issue_comment' && github.event.issue.pull_request &&
(contains(github.event.comment.body, '@prod-igy') || contains(github.event.comment.body, '/prod-igy')))
and the job holds pull-requests: write, issues: write and the PRODIGY_APP_ID installation token. Neither the workflow if: nor prod-igy.js's issue_comment handler…
Read the thread · 2026-09-19 · closed · 1 comment
Most recent
mcp 1.x is documented as supported but hangs on the first tool call (the #90 hang)
Found while switching CI to the committed lockfile in #406.
What happens
Under mcp 1.30.0, the MCP server never answers its first tool call on the parallel path:
FAILED tests/test_mcp.py::test_iss90_tools_call_over_serve_completes_on_the_parallel_path
AssertionError: no JSON-RPC response within 240s (the #90 hang)
Deterministic — reproduced 2/2, ~4 minutes each. Under mcp 2.2.0 the same test passes in 1.9s.
Why it matters
1.x is not an accident of resolution, it is…
Read the thread · 2026-09-22 · open · 0 comments
[P2] HTTP transport advertises protocolVersion 2025-06-18 but does not implement Streamable HTTP
Summary
initialize responds with "protocolVersion": "2025-06-18". That revision's HTTP transport is Streamable HTTP: a single endpoint supporting POST for requests and GET for an SSE stream, an Mcp-Session-Id header for session binding, Last-Event-ID for resumability, and text/event-stream responses when the server chooses to stream.
What is implemented is a plain JSON-RPC-over-POST endpoint: Content-Length framing only, HTTP/1.0 with close_connection after every…
Read the thread · 2026-09-22 · open · 0 comments
[P2] Warn when the index is stale relative to the working tree
Summary
The MCP server detects that the index was rebuilt by someone else — _index_mtime compares manifest.json's mtime and reloads. It does not detect that the working tree moved underneath the index. A long-running server therefore answers from a stale graph indefinitely, and says nothing.
Evidence
repo2graph/mcp.py:272-276
def _index_mtime(out_path: Path) -> float:
...
return target.stat().st_mtime if target.is_file() else 0.0
and :338-341…
Read the thread · 2026-09-22 · open · 0 comments
[P2] Apply the Host and Origin check to GET and HEAD, not only POST
Summary
do_POST and do_OPTIONS both validate Host and Origin before anything else runs — exactly right, and the module docstring explains why (DNS rebinding against a loopback bind). do_GET and do_HEAD do not.
The worst of this was fixed by fb903b7 (_public_repo_label publishes the basename, not the absolute path). What remains is that a page open in the user's browser can still read /.well-known/mcp-server-metadata and /healthz cross-origin: the repo basename, whether an…
Read the thread · 2026-09-22 · open · 0 comments
[P2] Enforce a minimum RSA modulus size and bound the public exponent in rsa_verify
Summary
rsa_verify rejects n <= 0 and e <= 0, then proceeds for any value above that. Two consequences:
- No minimum modulus. A 512-bit RSA key published in a JWKS verifies happily. The signature maths is correct; the key is simply not strong enough to mean anything.
- Unbounded exponent.
pow(int.from_bytes(signature, "big"), e, n)with a hostile multi-thousand-biteis a CPU sink, reachable once per request on thedecode_jwtpath.MAX_JWKS_BYTES(1 MiB) bounds the…
Read the thread · 2026-09-22 · open · 0 comments
mcp: --http-only without --http-port silently serves stdio, and audit.close() is unreachable on that path
Two defects on the same code path (repo2graph/mcp.py:920-955), both stemming from --http-only living inside the block that builds the transport.
1. --http-only with no --http-port silently serves stdio. The transport is only constructed under:
if args.http_port is not None or args.auth_cimd:
...
transport.start()
if args.http_only:
...
return 0
elif auth_config.enabled:
raise SystemExit(...)
With --http-only alone, neither…
Read the thread · 2026-09-19 · closed · 1 comment
audit: the high_entropy rule redacts ordinary identifier queries out of the audit log
Problem. _looks_like_a_secret (repo2graph/audit.py:113-120) treats any long unbroken run of token characters as a credential:
if len(value) >= ENTROPY_MIN_LEN and re.fullmatch(r"[A-Za-z0-9+/=_-]+", value):
digits = sum(c.isdigit() for c in value)
letters = sum(c.isalpha() for c in value)
if digits and letters:
return "high_entropy"
_ is in that character class, so a snake_case identifier of 24+ characters containing at least one digit matches.…
Read the thread · 2026-09-19 · closed · 1 comment
http_server: _send_json misses ConnectionAbortedError and leaves end_headers() outside its guard, leaking tracebacks into the JSON-lines stderr stream
Problem. _send_json (repo2graph/http_server.py:160-174) guards only the body write, and only against two of the several exceptions a disconnect can raise:
self.send_response(status)
self.send_header(...)
self.end_headers() # <- flushes; outside the try
try:
self.wfile.write(body)
except (BrokenPipeError, ConnectionResetError):
return
Two gaps:
ConnectionAbortedErroris neither of the two caught types (all three are siblings under…
Read the thread · 2026-09-19 · closed · 1 comment
The remaining reports are on the project's issue tracker.