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

  1. If you are running litmus, this is the expected pass response — no action needed
  2. If a real client sends this header unintentionally, remove the X-Litmus header from the request
  3. 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

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


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/01e0fc66fa7f26c0. Report an issue: GitHub.