juicedata/juicefs · error
400 Bad Request
Error message
400 Bad Request
What it means
The WebDAV handler in pkg/fs/http.go returns a literal '400 Bad Request' body when it detects the litmus conformance test case 'props: 3 (propfind_invalid2)', which sends a malformed PROPFIND XML body. The RFC4918 suite historically expected servers to reject invalid namespace declarations; the handler hard-codes this response for that specific test header.
Source
Thrown at pkg/fs/http.go:329
//
// If a request was sent with an XML body which included an empty namespace
// prefix declaration (xmlns:ns1=""), then the server must reject that with
// a "400 Bad Request" response, as it is invalid according to the XML
// Namespace specification."
//
// On the other hand, the Go standard library's encoding/xml package
// accepts an empty xmlns namespace, as per the discussion at
// https://github.com/golang/go/issues/8068
//
// Empty namespaces seem disallowed in the second (2006) edition of the XML
// standard, but allowed in a later edition. The grammar differs between
// http://www.w3.org/TR/2006/REC-xml-names-20060816/#ns-decl and
// http://www.w3.org/TR/REC-xml-names/#dt-prefix
//
// Thus, we assume that the propfind_invalid2 test is obsolete, and
// hard-code the 400 Bad Request response that the test expects.
if r.Header.Get("X-Litmus") == "props: 3 (propfind_invalid2)" {
http.Error(w, "400 Bad Request", http.StatusBadRequest)
return
}
if !h.EnableProppatch && r.Method == "PROPPATCH" {
http.Error(w, "The PROPPATCH method is not currently enabled,please add the --enable-proppatch parameter and run it again", http.StatusNotImplemented)
return
}
h.Handler.ServeHTTP(w, r)
}
func newWebdavHandler(fs *FileSystem, config WebdavConfig) http.Handler {
ctx := meta.NewContext(uint32(os.Getpid()), uint32(utils.GetCurrentUID()), []uint32{uint32(utils.GetCurrentGID())})
hfs := &webdavFS{ctx, fs, uint16(utils.GetUmask()), config}
srv := &webdav.Handler{
FileSystem: hfs,
LockSystem: webdav.NewMemLS(),
Logger: func(r *http.Request, err error) {View on GitHub (pinned to c9a67b23e8)
Solutions
- If you are running litmus, this is the expected pass response — no action needed
- If a real client sends this header unintentionally, remove the X-Litmus header from the request
- For genuinely malformed PROPFIND XML (without the header), fix the client's XML namespace declarations
Example fix
// before
req.Header.Set("X-Litmus", "props: 3 (propfind_invalid2)")
// after
req.Header.Del("X-Litmus") // send a well-formed PROPFIND body instead Defensive patterns
Strategy: validation
Validate before calling
// Don't send litmus test headers in production clients
if strings.HasPrefix(r.Header.Get("X-Litmus"), "props:") { strip header before sending } Type guard
func isLitmusProbe(h http.Header) bool { return h.Get("X-Litmus") != "" } Prevention
- Never set X-Litmus headers outside conformance test runs
- Send well-formed PROPFIND XML with correct namespace declarations
- Use litmus only against dedicated test volumes
When it happens
Trigger: Sending a PROPFIND request with header 'X-Litmus: props: 3 (propfind_invalid2)' to the WebDAV endpoint; also any client that happens to set this header. Ordinary malformed PROPFIND bodies are handled by golang.org/x/net/webdav, not this branch.
Common situations: Running the litmus WebDAV compliance test suite against a JuiceFS WebDAV mount; proxy or test harness replaying recorded litmus traffic.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Forbidden
- The PROPPATCH method is not currently enabled,please add the
- error creating GET request: %v
- error GET request: %v
- error GET request, status code %d
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/01e0fc66fa7f26c0.
Report an issue: GitHub.