A language-model request the provider did not answer with a completion.
Imp.Clients.ReqLLM returns {:error, %Imp.LMError{}} for every failed
request: an HTTP error status, an error the provider relayed inside a
successful response, a connection that failed, and an exception raised
inside the provider library. A caller decides what to do from three fields
without matching the provider library's own terms:
:status— the HTTP status the provider answered with, ornilwhen no response came back.:retryable—truewhen sending the same request again may succeed. That is so when the provider says to try later (a 408, 425, 429 or 5xx status), and when the request provably never reached the provider (the connection was refused, no pooled connection was free, or it closed or timed out before the request was sent). For any other status it is ReqLLM's ownretryablewhen ReqLLM set one, andfalseotherwise; a 409 is never retryable. It is alsotruefor a timeout while waiting for the answer and for a stream that failed after it started: those requests may have run and been billed, and a retried stream repeats the chunks the caller already has. A response or stream of a shape ReqLLM never returns isfalse.:context_window_exceeded—truewhen the provider refused the request because its input is longer than the model accepts. Sending it again unchanged will fail again; a shorter input may not.
:reason keeps the provider library's error unchanged for diagnostics.
Imp.Errors.retryable?/1 and Imp.Errors.context_window_exceeded?/1 read
these fields through the wrappers Imp puts around an LM error.
A client that raises instead of returning is not an Imp.LMError: Imp.LM
returns {:lm_failed, client, exception}, because a crash in the client says
nothing about the provider.
Summary
Types
@type t() :: %Imp.LMError{ __exception__: true, context_window_exceeded: boolean(), message: String.t() | nil, reason: term(), retryable: boolean(), status: non_neg_integer() | nil }