windmill-labs/windmill · error

Could not generate OpenAPI document in JSON format: {}

Error message

Could not generate OpenAPI document in JSON format: {}

What it means

Same as the YAML variant: generate_openapi_document serializes the OpenAPI document to pretty JSON via serde_json::to_string_pretty, wrapping failures as 'Could not generate OpenAPI document in JSON format: {}'. Thrown when the assembled document cannot be converted to a JSON string.

Source

Thrown at backend/windmill-api-openapi/src/lib.rs:644

    openapi_doc.insert("openapi", to_value(&DEFAULT_OPENAPI_GENERATED_VERSION)?);
    openapi_doc.insert(
        "info",
        to_value(info.unwrap_or(&DEFAULT_OPENAPI_INFO_OBJECT))?,
    );

    openapi_doc.insert("components", Value::Object(generate_components(&paths)));

    openapi_doc.insert("paths", to_value(generate_paths(paths, url)?)?);

    let openapi_document = match format {
        Format::YAML => serde_yml::to_string(&openapi_doc).map_err(|err| {
            anyhow!(
                "Could not generate OpenAPI document in YAML format: {}",
                err
            )
        })?,
        Format::JSON => serde_json::to_string_pretty(&openapi_doc).map_err(|err| {
            anyhow!(
                "Could not generate OpenAPI document in JSON format: {}",
                err
            )
        })?,
    };

    Ok(openapi_document)
}

#[allow(unused)]
#[derive(Debug, Deserialize)]
struct HttpRouteFilter {
    folder_regex: String,
    path_regex: String,
    route_path_regex: String,
}

#[derive(Debug, Deserialize)]

View on GitHub (pinned to e474e8803c)

Solutions

  1. Read the wrapped serde_json error to locate the offending value and fix the generator inserting it
  2. Ensure numeric defaults/schemas never contain NaN or Infinity
  3. Verify all inserted values are valid serde_json::Value instances (use to_value and handle errors)
  4. Check serde_json version consistency in the workspace

Example fix

// before
let default = f64::NAN;
"default": serde_json::json!(default) // not JSON-representable
// after
"default": serde_json::json!(0.0)
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure values are JSON-safe before insertion
let v = serde_json::to_value(&schema)?; // rejects NaN etc. via custom serializer
assert!(v.as_f64().map(|f| f.is_finite()).unwrap_or(true));

Try / catch

match generate_openapi_document(paths, url, Format::JSON) {
    Ok(doc) => doc,
    Err(e) if e.to_string().contains("JSON format") => {
        tracing::error!("json spec generation failed: {e:#}");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling generate_openapi_document (via generate_openapi_spec or download_spec) with format=JSON when the document contains values serde_json cannot serialize (NaN floats, non-string map keys created via serde_json::Value maps, non-JSON types inserted by generators).

Common situations: A path/component generator inserts an invalid serde_json::Value (e.g. from to_value on a non-serializable struct); float NaN in schema defaults; a recent code change added a component with exotic types.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/8599f8e29b034b24. Report an issue: GitHub.