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 transport failed with no response: the connection was refused or no pooled connection was free, which say the request never reached the provider, or the connection closed or timed out, which may have happened after 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 stream that failed after it started. A timeout, a closed connection, a 5xx other than 503 or 529 and a failed stream may follow a request that ran and was billed, and a retried stream repeats the chunks the caller already has;retryablesays a retry may succeed, not that it is safe. 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.:content_filtered—truewhen the provider's content filter stopped the completion (finish_reason: :content_filter). Such a request is not retryable: sent again unchanged, it is likely to be filtered, and billed, again.
An error the provider sends inside a stream arrives without its code,
because ReqLLM's stream decoder keeps only its message, so it has :status
nil and is retryable as a failed stream, where the same error in a
non-streamed response may carry a status that says otherwise.
: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.