GopeedLab/gopeed · error
method not allowed
Error message
method not allowed
What it means
The registry serves blobs from a loopback HTTP server (paths under /__blob/) and its handler is read-only: only GET is accepted. ServeHTTP rejects every other method with 405 and an 'Allow: GET' response header before it even parses the blob ID, so the rejection is independent of whether the blob exists. Any HEAD, POST, PUT, DELETE, or OPTIONS request to a blob URL gets this response.
Source
Thrown at internal/blob/registry.go:311
if err != nil {
return "", err
}
r.listener = listener
r.baseURL = "http://" + listener.Addr().String() + urlPathPrefix
server := &http.Server{Handler: r}
r.server = server
go func() {
if err := server.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
_ = r.Close()
}
}()
return r.baseURL, nil
}
func (r *Registry) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodGet {
w.Header().Set("Allow", "GET")
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
id := parseRequest(req)
if id == "" {
http.NotFound(w, req)
return
}
src, err := r.getByID(id)
if err != nil {
http.NotFound(w, req)
return
}
meta, open, session := src.acquireOpen()
if open == nil {
http.NotFound(w, req)
return
}
if session != nil {View on GitHub (pinned to 7b7327ffb3)
Solutions
- Change the request to GET — it is the only method the endpoint serves
- From Go, skip HTTP probing entirely: use Registry.IsURL(url) or Registry.Metadata(url) to check a blob
- If you mount the registry behind your own mux, route only GET to /__blob/ and answer other methods yourself
- When debugging, read the 'Allow: GET' response header to confirm the supported method set
Example fix
// before
resp, err := http.Head(blobURL) // 405 method not allowed
// after
resp, err := http.Get(blobURL)
// existence checks from Go code:
if reg.IsURL(blobURL) { /* source registered */ } Defensive patterns
Strategy: validation
Validate before calling
// blob URLs are GET-only: gate the method before issuing the request
if method != http.MethodGet {
return fmt.Errorf("blob endpoint is GET-only, got %s", method)
}
req, err := http.NewRequest(http.MethodGet, blobURL, nil)
if err != nil {
return err
} Try / catch
resp, err := client.Get(blobURL)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusMethodNotAllowed { // 405
// wrong method; only GET is served (resp.Header.Get("Allow") == "GET")
return fmt.Errorf("blob endpoint rejected %s; use GET", method)
} Prevention
- Treat blob URLs as read-only GET resources
- Use Registry.IsURL / Registry.Metadata instead of HTTP HEAD probes
- When a 405 appears, check the Allow header before assuming the blob is missing
When it happens
Trigger: Issuing any non-GET request to a URL returned by Registry.CreateBlob/CreateOpener, e.g. http.Head(blobURL) for an existence probe, or a generic HTTP client whose default method is POST. The method check at registry.go:309 runs first, so even HEAD on a valid, live blob URL returns 405.
Common situations: Health/existence checks written with http.Head; download frameworks that probe servers with OPTIONS or HEAD before GETting; axios/fetch calls that default to POST; wrapping code that forwards all methods to the registry handler unchanged.
Related errors
- redirect failed
- too many redirects
- invalid range
- connection %d failed: retries=%d, status=%d
- redirect failed
AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16).
Data as JSON: /api/errors/8ab6428682f63529.
Report an issue: GitHub.