Summary
Every ClawHub skill install from the dashboard fails with HTTP 422 Unprocessable Entity. The install never reaches the handler — the request body is rejected at the Json<ClawHubInstallRequest> extractor.
Reproduction
Click "Install" on any ClawHub skill in the dashboard (Skills page). The request fails silently. Reproduced directly against the API:
$ curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:4545/api/clawhub/install \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"slug":"github-helper","version":"latest","hand":null}'
422
Response body:
Failed to deserialize the JSON body into the target type: version: unknown field `version`, expected `slug` or `hand`
It fails even with a valid slug, so it is not a missing-field problem — it is the extra version field being rejected.
Root cause
The dashboard always sends a version field (crates/librefang-api/dashboard/src/api.ts, clawhubInstall):
post("/api/clawhub/install", { slug, version: version || "latest", hand }, ...)
But the backend request type denies unknown fields and has no version field (crates/librefang-api/src/types.rs):
#[derive(Debug, Deserialize, utoipa::ToSchema)]
#[serde(deny_unknown_fields)]
pub struct ClawHubInstallRequest {
pub slug: String,
#[serde(default)]
pub hand: Option<String>,
}
deny_unknown_fields + the dashboard's version => the axum Json extractor returns 422 before the handler runs. This affects all ClawHub installs via the dashboard, on current main.
Impact
ClawHub skill installation from the dashboard is completely broken. The China-mirror handler (clawhub_cn_install) uses the same request type and is affected identically.
Proposed fix
Accept the field the dashboard already sends: add version: Option<String> with #[serde(default)] to ClawHubInstallRequest. The installer currently resolves to the latest published version (client.install(slug, dir) takes no version), so the field is accepted to keep the request well-formed rather than driving version selection yet. PR incoming.
Summary
Every ClawHub skill install from the dashboard fails with HTTP 422 Unprocessable Entity. The install never reaches the handler — the request body is rejected at the
Json<ClawHubInstallRequest>extractor.Reproduction
Click "Install" on any ClawHub skill in the dashboard (Skills page). The request fails silently. Reproduced directly against the API:
Response body:
It fails even with a valid
slug, so it is not a missing-field problem — it is the extraversionfield being rejected.Root cause
The dashboard always sends a
versionfield (crates/librefang-api/dashboard/src/api.ts,clawhubInstall):But the backend request type denies unknown fields and has no
versionfield (crates/librefang-api/src/types.rs):deny_unknown_fields+ the dashboard'sversion=> the axumJsonextractor returns 422 before the handler runs. This affects all ClawHub installs via the dashboard, on currentmain.Impact
ClawHub skill installation from the dashboard is completely broken. The China-mirror handler (
clawhub_cn_install) uses the same request type and is affected identically.Proposed fix
Accept the field the dashboard already sends: add
version: Option<String>with#[serde(default)]toClawHubInstallRequest. The installer currently resolves to the latest published version (client.install(slug, dir)takes no version), so the field is accepted to keep the request well-formed rather than driving version selection yet. PR incoming.