From 1a19683ee68aee8fe170ace18251056993f73276 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 1 Jun 2026 12:20:45 -0700 Subject: [PATCH] filer: name the read-only path in the write rejection (#9773) * filer: name the read-only path in the write rejection The write path rejected creates under a read-only rule with a bare "read only", giving no hint which path was locked or why. Wrap the error with the matched location prefix and a quota hint so a FUSE mkdir or S3 put points straight at the offending bucket. * return the read-only reason over HTTP and drop any query string from the fallback prefix --- weed/server/filer_server_handlers_write.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/weed/server/filer_server_handlers_write.go b/weed/server/filer_server_handlers_write.go index 971fef973..267968c46 100644 --- a/weed/server/filer_server_handlers_write.go +++ b/weed/server/filer_server_handlers_write.go @@ -98,8 +98,8 @@ func (fs *FilerServer) PostHandler(w http.ResponseWriter, r *http.Request, conte query.Get("saveInside"), ) if err != nil { - if err == ErrReadOnly { - w.WriteHeader(http.StatusInsufficientStorage) + if errors.Is(err, ErrReadOnly) { + writeJsonError(w, r, http.StatusInsufficientStorage, err) } else { glog.V(1).InfolnCtx(ctx, "post", r.RequestURI, ":", err.Error()) w.WriteHeader(http.StatusInternalServerError) @@ -255,7 +255,14 @@ func (fs *FilerServer) detectStorageOption(ctx context.Context, requestURI, qCol rule := fs.filer.FilerConf.MatchStorageRule(requestURI) if rule.ReadOnly { - return nil, ErrReadOnly + // Name the read-only prefix so the caller knows which path is locked and why. + // MatchStorageRule leaves LocationPrefix empty when several rules merge; fall back to the request path. + prefix := rule.LocationPrefix + if prefix == "" { + // requestURI may carry a query string on the HTTP path; keep only the path. + prefix, _, _ = strings.Cut(requestURI, "?") + } + return nil, fmt.Errorf("%w: %s (e.g. bucket over quota)", ErrReadOnly, prefix) } // Use local variable instead of mutating shared rule