geektutu/7days-golang · warning
bad request
Error message
bad request
What it means
geecache's HTTPPool.ServeHTTP only understands URLs of the form /<basePath>/<groupName>/<key>. When the path after basePath splits on '/' into fewer than 2 segments, it responds with HTTP 400 and body 'bad request'. It is the library telling you the request URL does not match the expected cache API shape.
Source
Thrown at gee-cache/day3-http-server/geecache/http.go:41
basePath: defaultBasePath,
}
}
// Log info with server name
func (p *HTTPPool) Log(format string, v ...interface{}) {
log.Printf("[Server %s] %s", p.self, fmt.Sprintf(format, v...))
}
// ServeHTTP handle all http requests
func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, p.basePath) {
panic("HTTPPool serving unexpected path: " + r.URL.Path)
}
p.Log("%s %s", r.Method, r.URL.Path)
// /<basepath>/<groupname>/<key> required
parts := strings.SplitN(r.URL.Path[len(p.basePath):], "/", 2)
if len(parts) != 2 {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
groupName := parts[0]
key := parts[1]
group := GetGroup(groupName)
if group == nil {
http.Error(w, "no such group: "+groupName, http.StatusNotFound)
return
}
view, err := group.Get(key)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
View on GitHub (pinned to cf36443821)
Solutions
- Send the full expected path: /<basePath>/<groupName>/<key>, e.g. GET /_geecache/groups/key1.
- Exclude this endpoint from health checks, or point health checks at a dedicated route (e.g. /healthz) served by a different handler.
- Check any reverse-proxy/ingress rewrite rules so they do not strip the group or key segment.
- URL-encode the key if it can contain '/' so SplitN still yields exactly two parts.
Example fix
// before: GET /_geecache/mygroup -> 400
http.Get("http://localhost:8001/_geecache/mygroup")
// after: include key
http.Get("http://localhost:8001/_geecache/mygroup/key1") Defensive patterns
Strategy: validation
Validate before calling
// validate the URL before calling the cache node
func validCacheURL(base, group, key string) bool {
return group != "" && key != "" && !strings.ContainsAny(key, "/?#")
}
// url := base + "/" + group + "/" + url.PathEscape(key) Prevention
- Always build cache URLs as basePath + "/" + group + "/" + escaped key — never hand-concatenate partial paths.
- Point health checks/load balancer probes at a separate route, not the geecache HTTPPool.
- Escape keys containing '/' with url.PathEscape before embedding them in the URL.
- Add an integration test that asserts 200 for a representative /group/key request.
When it happens
Trigger: An HTTP request to the pool whose path after basePath contains fewer than two '/'-separated parts, e.g. GET /_geecache/ or GET /_geecache/mygroup (missing the /<key> segment).
Common situations: Health checks or load balancers hitting the pool's base path directly; a client forgetting to append /<key>; proxy rewriting that strips part of the path; typos like a trailing-slash-only URL.
Related errors
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/8be1527df24247a6.
Report an issue: GitHub.