theonedev/onedev · error · ClientException

Method Not Allowed

Error message

Method Not Allowed

What it means

The Cargo pack registry handler routes requests under /api/v1/crates/... . Cargo's publish endpoint (/api/v1/crates/new) only accepts PUT (as cargo client uses) and download endpoints only accept GET; any other HTTP method on those paths results in a ClientException with status 405 Method Not Allowed.

Source

Thrown at server-plugin/server-plugin-pack-cargo/src/main/java/io/onedev/server/plugin/pack/cargo/CargoPackHandler.java:106

		this.objectMapper = objectMapper;
	}

	@Override
	public String getHandlerId() {
		return HANDLER_ID;
	}

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
					   Long projectId, Long buildId, List<String> pathSegments) {
		var method = request.getMethod();
		var isGet = method.equals("GET");
		var isPut = method.equals("PUT");
		var isDelete = method.equals("DELETE");

		if (pathSegments.equals(newArrayList("api", "v1", "crates", "new"))) {
			if (!isPut)
				throw new ClientException(SC_METHOD_NOT_ALLOWED);
			publish(request, response, projectId, buildId);
		} else if (pathSegments.size() == 6
				&& pathSegments.subList(0, 3).equals(newArrayList("api", "v1", "crates"))
				&& pathSegments.get(5).equals("download")) {
			if (!isGet)
				throw new ClientException(SC_METHOD_NOT_ALLOWED);
			download(response, projectId, decodePath(pathSegments.get(3)), decodePath(pathSegments.get(4)));
		} else if (pathSegments.size() == 6
				&& pathSegments.subList(0, 3).equals(newArrayList("api", "v1", "crates"))
				&& pathSegments.get(5).equals("yank")) {
			if (!isDelete)
				throw new ClientException(SC_METHOD_NOT_ALLOWED);
			setYanked(response, projectId, decodePath(pathSegments.get(3)), decodePath(pathSegments.get(4)), true);
		} else if (pathSegments.size() == 6
				&& pathSegments.subList(0, 3).equals(newArrayList("api", "v1", "crates"))
				&& pathSegments.get(5).equals("unyank")) {
			if (!isPut)
				throw new ClientException(SC_METHOD_NOT_ALLOWED);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Use the cargo client itself: `cargo publish` issues PUT to /api/v1/crates/new; `cargo` download uses GET.
  2. If testing manually, send `curl -X PUT` for publish (with the cargo payload) and plain GET for download URLs.
  3. Check any reverse proxy/rewrite rules that may convert request methods.

Example fix

// before
curl -X POST https://onedev.example.com/~builds/1/api/v1/crates/new ...
// after
curl -X PUT https://onedev.example.com/~builds/1/api/v1/crates/new ...
Defensive patterns

Strategy: validation

Validate before calling

const allowed = {"/api/v1/crates/new": ["PUT"], "/api/v1/crates/download": ["GET"]};
if (!allowed[pathKey]?.includes(method)) throw new Error("Wrong HTTP method for " + pathKey);

Try / catch

try {
    await publishPackage();
} catch (e) {
    if (e.response && e.response.status === 405) {
        console.error("Method not allowed: use PUT for publish, GET for download");
    }
}

Prevention

When it happens

Trigger: Sending POST/GET to /api/v1/crates/new instead of PUT, or POST/PUT/DELETE to a /api/v1/crates/{crate}/{version}/download path instead of GET.

Common situations: Manually testing the registry with curl using the wrong verb; a proxy or tool rewriting PUT to POST; scripts using generic REST conventions (POST to publish) against the cargo-compatible API.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/cd93446396f31449. Report an issue: GitHub.