Summary
When the target endpoint returns a transient HTTP error (observed: 408 REQUEST TIMEOUT) for a
single generation, garak.generators.nim raises a fatal GarakException that propagates out of the
probe's worker pool and aborts the entire probe run mid-way. In addition, the exception message
("NIM generation failed. Is the model name spelled correctly?") is misleading — the model name was
correct; the real cause was an HTTP timeout.
Environment
- garak version path:
/opt/venv/lib/python3.12/site-packages/garak/
- Target: an OpenAI-compatible endpoint fronted by a load-balancing proxy, backed by a slow reasoning model
- Probe:
leakreplay.LiteratureCloze (256 samples), max_tokens=32768
- Run context: garak run driven by nemo-evaluator-launcher on Slurm
What happened
The LB proxy in front of the model returned 408 REQUEST TIMEOUT after the model (a slow reasoning
model at 32k max tokens) exceeded the request timeout. garak's NIM generator turned that single failed
generation into a fatal exception, killing the probe at attempt 48/256. No detector/eval pass ran,
so the run produced attempts but zero eval entries in results.report.jsonl.
Evidence
Backend error (client/proxy log):
httpx.HTTPStatusError: Client error '408 REQUEST TIMEOUT' for url 'http://localhost:3825/chat/completions'
garak traceback (artifacts/garak/garak.log):
2026-07-14 03:31:10 CRITICAL NIM generation failed. Is the model name spelled correctly?
...
File "/opt/venv/lib/python3.12/site-packages/garak/generators/nim.py", line 101, in _call_model
raise GarakException(f"🛑 {msg}") from oe
garak.exception.GarakException: 🛑 NIM generation failed. Is the model name spelled correctly?
The above exception was the direct cause of the following exception:
File "/opt/venv/lib/python3.12/site-packages/garak/cli.py", line 614, in main
command.probewise_run(...)
File "/opt/venv/lib/python3.12/site-packages/garak/harnesses/probewise.py", line 109, in run
File "/opt/venv/lib/python3.12/site-packages/garak/harnesses/base.py", line 151, in run
attempt_results = probe.probe(model)
File "/opt/venv/lib/python3.12/site-packages/garak/probes/base.py", line 449, in probe
attempts_completed = self._execute_all(attempts_todo)
File "/opt/venv/lib/python3.12/site-packages/garak/probes/base.py", line 335, in _execute_all
for result in attempt_pool.imap_unordered(...)
File "/usr/lib/python3.12/multiprocessing/pool.py", line 873, in next
raise value
garak.exception.GarakException: 🛑 NIM generation failed. Is the model name spelled correctly?
Resulting report (results.report.jsonl) entry-type counts — note no eval:
{'start_run setup': 1, 'init': 1, 'attempt': 48}
(4 occurrences of NIM generation failed appeared in garak.log over the run.)
Root cause (confirmed against main)
The retry gap is specific. OpenAICompatible._call_model in garak/generators/openai.py retries only a
fixed set of exceptions via its backoff decorator:
@backoff.on_exception(
backoff.fibo,
(
openai.RateLimitError, # 429
openai.InternalServerError, # 5xx
openai.APITimeoutError, # client-side read timeout (no HTTP status)
openai.APIConnectionError,
garak.exception.GeneratorBackoffTrigger,
),
max_value=70,
)
A server-issued HTTP 408 REQUEST TIMEOUT does not map to any of these. In the OpenAI SDK, 408 has no
dedicated exception subclass, so it is raised as a generic openai.APIStatusError. That class is:
- not in the backoff tuple above → it is never retried, and
- not handled by any specific
except block in OpenAICompatible._call_model (which only catches
AuthenticationError/PermissionDeniedError, BadRequestError, and JSONDecodeError).
So the 408 propagates up into NVOpenAIChat._call_model (garak/generators/nim.py), where the catch-all
except Exception (see below) turns it into a fatal GarakException that aborts the whole probe.
garak/generators/nim.py, NVOpenAIChat._call_model (current main):
except Exception as oe:
msg = "NIM generation failed. Is the model name spelled correctly?"
logging.critical(msg, exc_info=oe)
raise GarakException(f"🛑 {msg}") from oe
Impact
- A single transient endpoint error (408, or other transient
APIStatusError codes such as 502/503/504
that are not InternalServerError) discards an entire probe's partial work — expensive for slow probes
that already ran for over an hour.
- The misleading "Is the model name spelled correctly?" message sends operators debugging a
configuration problem that does not exist, when the real issue is a transient HTTP timeout.
Requests
- Add transient HTTP status codes to the retry/backoff set. At minimum 408, and consider 502/503/504.
These currently arrive as openai.APIStatusError and bypass the backoff decorator entirely. Retrying
them (with the existing fibo backoff) would avoid killing the probe on a single transient hiccup.
- Do not abort the whole probe on a single unhandled generation error. Rather than the NIM subclass's
catch-all except Exception raising a fatal GarakException out of the worker pool, record the attempt
as failed and continue (or retry), so one bad request does not discard 250+ completed samples.
- Fix the error message. Report the actual HTTP status / underlying error (e.g. "HTTP 408 Request
Timeout from ") instead of the generic "Is the model name spelled correctly?" — the latter is
misleading for any non-2xx that is not a genuine 404/400.
Notes
This surfaced downstream as a "job COMPLETED but no results" anomaly because the Slurm wrapper reported
exit 0 despite this crash (that wrapper behavior is a separate issue filed against nemo-evaluator-launcher).
The garak-side ask here is independent: be resilient to transient endpoint errors and report the real cause.
Related but distinct: #1466 (a separate NIM-client crash — file-descriptor leak on long runs).
Summary
When the target endpoint returns a transient HTTP error (observed: 408 REQUEST TIMEOUT) for a
single generation,
garak.generators.nimraises a fatalGarakExceptionthat propagates out of theprobe's worker pool and aborts the entire probe run mid-way. In addition, the exception message
(
"NIM generation failed. Is the model name spelled correctly?") is misleading — the model name wascorrect; the real cause was an HTTP timeout.
Environment
/opt/venv/lib/python3.12/site-packages/garak/leakreplay.LiteratureCloze(256 samples),max_tokens=32768What happened
The LB proxy in front of the model returned
408 REQUEST TIMEOUTafter the model (a slow reasoningmodel at 32k max tokens) exceeded the request timeout. garak's NIM generator turned that single failed
generation into a fatal exception, killing the probe at attempt 48/256. No detector/eval pass ran,
so the run produced attempts but zero
evalentries inresults.report.jsonl.Evidence
Backend error (client/proxy log):
garak traceback (
artifacts/garak/garak.log):Resulting report (
results.report.jsonl) entry-type counts — note noeval:(4 occurrences of
NIM generation failedappeared in garak.log over the run.)Root cause (confirmed against
main)The retry gap is specific.
OpenAICompatible._call_modelingarak/generators/openai.pyretries only afixed set of exceptions via its backoff decorator:
A server-issued HTTP 408 REQUEST TIMEOUT does not map to any of these. In the OpenAI SDK, 408 has no
dedicated exception subclass, so it is raised as a generic
openai.APIStatusError. That class is:exceptblock inOpenAICompatible._call_model(which only catchesAuthenticationError/PermissionDeniedError,BadRequestError, andJSONDecodeError).So the 408 propagates up into
NVOpenAIChat._call_model(garak/generators/nim.py), where the catch-allexcept Exception(see below) turns it into a fatalGarakExceptionthat aborts the whole probe.garak/generators/nim.py,NVOpenAIChat._call_model(currentmain):Impact
APIStatusErrorcodes such as 502/503/504that are not
InternalServerError) discards an entire probe's partial work — expensive for slow probesthat already ran for over an hour.
configuration problem that does not exist, when the real issue is a transient HTTP timeout.
Requests
These currently arrive as
openai.APIStatusErrorand bypass the backoff decorator entirely. Retryingthem (with the existing fibo backoff) would avoid killing the probe on a single transient hiccup.
catch-all
except Exceptionraising a fatalGarakExceptionout of the worker pool, record the attemptas failed and continue (or retry), so one bad request does not discard 250+ completed samples.
Timeout from ") instead of the generic "Is the model name spelled correctly?" — the latter is
misleading for any non-2xx that is not a genuine 404/400.
Notes
This surfaced downstream as a "job COMPLETED but no results" anomaly because the Slurm wrapper reported
exit 0 despite this crash (that wrapper behavior is a separate issue filed against nemo-evaluator-launcher).
The garak-side ask here is independent: be resilient to transient endpoint errors and report the real cause.
Related but distinct: #1466 (a separate NIM-client crash — file-descriptor leak on long runs).