In 1.x, HTTP.Exceptions was an internal organizational submodule (include("Exceptions.jl"); using .Exceptions, like Messages/Connections), and the using re-exported the types to the top level. The documented names were the top-level ones — HTTP.StatusError, HTTP.ConnectError, HTTP.TimeoutError — and those still resolve in 2.x (v2.3.0). What's gone is the HTTP.Exceptions submodule itself (isdefined(HTTP, :Exceptions) == false), so code reaching in via HTTP.Exceptions.StatusError breaks.
It's easy to miss because the reference sits in a catch block:
try
HTTP.get(url)
catch e
if e isa HTTP.Exceptions.StatusError && e.status == 429
...
end
end
That compiles, precompiles, and passes its happy-path tests, then throws UndefVarError: Exceptions not defined in HTTP the first time a real error reaches the catch — silent until production, unlike the readtimeout deprecation which warns. The migration guide covers readtimeout → read_idle_timeout but not this — and it's not rare: a GitHub code search returns 40 repos using HTTP.Exceptions.StatusError and 13 using HTTP.Exceptions.RequestError, including AWS.jl, PromptingTools.jl, and WebSockets.jl (this org).
The 7 names 1.x's Exceptions exported split cleanly:
| name(s) |
in 2.x |
suggested |
HTTPError · StatusError · ConnectError · TimeoutError |
top-level in HTTP |
deprecating re-export (below) |
RequestError |
removed, no equivalent ¹ |
migration-guide note |
@try · current_exceptions_to_string |
removed |
copy back if wanted (trivial) |
¹ RequestError (thrown, fields .request/.error) has no drop-in: 2.x lets the underlying exception propagate, with isrecoverable(err) as the classifier (made public in #1310). RequestRetryError is the retry_if wrapper (field .err), not what's thrown — so restoring it means reintroducing the type and its throw sites, a behavior change, not a shim.
For the four that just moved, a small deprecating submodule keeps old code working and nudges migration (slots into src/HTTP.jl before end # module):
module Exceptions
import ..HTTP
Base.@deprecate_binding StatusError HTTP.StatusError false
Base.@deprecate_binding ConnectError HTTP.ConnectError false
Base.@deprecate_binding TimeoutError HTTP.TimeoutError false
Base.@deprecate_binding HTTPError HTTP.HTTPError false
end
HTTP.Exceptions.StatusError resolves again, forwards to HTTP.StatusError, and depwarns under --depwarn=yes / in tests — silent in production.
This mirrors the manual-Cookie gap (#1283), where the docs-only note (#1284) gave way to restoring the behavior (#1287); and #1267, where you were "open to … easy/simple things we can add back to 2.X for compat." So: the deprecating shim for the four moved types plus a migration-1x.md note for RequestError, or a note only? Happy to PR either.
In 1.x,
HTTP.Exceptionswas an internal organizational submodule (include("Exceptions.jl"); using .Exceptions, likeMessages/Connections), and theusingre-exported the types to the top level. The documented names were the top-level ones —HTTP.StatusError,HTTP.ConnectError,HTTP.TimeoutError— and those still resolve in 2.x (v2.3.0). What's gone is theHTTP.Exceptionssubmodule itself (isdefined(HTTP, :Exceptions) == false), so code reaching in viaHTTP.Exceptions.StatusErrorbreaks.It's easy to miss because the reference sits in a
catchblock:That compiles, precompiles, and passes its happy-path tests, then throws
UndefVarError: Exceptions not defined in HTTPthe first time a real error reaches thecatch— silent until production, unlike thereadtimeoutdeprecation which warns. The migration guide coversreadtimeout→read_idle_timeoutbut not this — and it's not rare: a GitHub code search returns 40 repos usingHTTP.Exceptions.StatusErrorand 13 usingHTTP.Exceptions.RequestError, including AWS.jl, PromptingTools.jl, and WebSockets.jl (this org).The 7 names 1.x's
Exceptionsexported split cleanly:HTTPError·StatusError·ConnectError·TimeoutErrorHTTPRequestError@try·current_exceptions_to_string¹
RequestError(thrown, fields.request/.error) has no drop-in: 2.x lets the underlying exception propagate, withisrecoverable(err)as the classifier (made public in #1310).RequestRetryErroris theretry_ifwrapper (field.err), not what's thrown — so restoring it means reintroducing the type and its throw sites, a behavior change, not a shim.For the four that just moved, a small deprecating submodule keeps old code working and nudges migration (slots into
src/HTTP.jlbeforeend # module):HTTP.Exceptions.StatusErrorresolves again, forwards toHTTP.StatusError, and depwarns under--depwarn=yes/ in tests — silent in production.This mirrors the manual-
Cookiegap (#1283), where the docs-only note (#1284) gave way to restoring the behavior (#1287); and #1267, where you were "open to … easy/simple things we can add back to 2.X for compat." So: the deprecating shim for the four moved types plus amigration-1x.mdnote forRequestError, or a note only? Happy to PR either.