Skip to content

ClawHub skill install always fails with 422: dashboard sends version but ClawHubInstallRequest denies unknown fields #6038

Description

@DaBlitzStein

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiREST/WS endpoints and dashboardarea/skillsSkill system and FangHub marketplacehas-prA pull request has been linked to this issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions