windmill-labs/windmill · error

{} is not valid json: {}

Error message

{} is not valid json: {}

What it means

read_and_check_file reads a JSON file from the job directory (usually a worker-produced output like result.json) and enforces the result-size limit. If the file content is not valid JSON, serde_json's parse error is wrapped in this message.

Source

Thrown at backend/windmill-worker/src/common.rs:480

}
/// Read the `result.json` file. This function assumes that the file contains valid json and will
/// result in undefined behaviour if it isn't. If the result.json is user generated or otherwise
/// not guaranteed to be valid, use `read_and_check_result`
pub async fn read_result(
    job_dir: &str,
    result_stream: Option<String>,
) -> error::Result<Box<RawValue>> {
    let rf = read_file(&format!("{job_dir}/result.json")).await;
    merge_result_stream(rf, result_stream).await
}

pub async fn read_and_check_file(path: &str) -> error::Result<Box<RawValue>> {
    let content = read_file_content(path).await?;

    check_result_too_big(content.len())?;

    let raw_value: Box<RawValue> =
        serde_json::from_str(&content).map_err(|e| anyhow!("{} is not valid json: {}", path, e))?;
    Ok(raw_value)
}

/// Use this to read `result.json` that were user-generated
pub async fn read_and_check_result(job_dir: &str) -> error::Result<Box<RawValue>> {
    let result_path = format!("{job_dir}/result.json");

    if let Ok(metadata) = tokio::fs::metadata(&result_path).await {
        if metadata.len() > 0 {
            return read_and_check_file(&result_path)
                .await
                .map_err(|e| anyhow!("Failed to read result: {}", e).into());
        }
    }
    Ok(to_raw_value(&json!("null")))
}

pub fn capitalize(s: &str) -> String {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Inspect the wrapped serde error (line/column) and fix the producing script to emit valid JSON
  2. Ensure the script serializes output with a JSON encoder (json.dumps / JSON.stringify) rather than raw print
  3. Check the file wasn't truncated (disk full, kill -9 mid-write); write atomically via temp file + rename
  4. If the file is intentionally non-JSON, don't place it where Windmill reads it as a result

Example fix

// before
result.json: {"result": 42,}
// after
result.json: {"result": 42}
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const raw = fs.readFileSync('result.json', 'utf8');
JSON.parse(raw); // throws early with position info if malformed

Type guard

function isValidJson(s: string): boolean {
  try { JSON.parse(s); return true; } catch { return false; }
}

Try / catch

try {
  const result = await runScriptAndGetResult();
} catch (e) {
  if (String(e.message).match(/is not valid json/)) {
    // inspect result.json at the reported line/column and fix the writer
  }
  throw e;
}

Prevention

When it happens

Trigger: A script writes result.json (or another file read via this helper) containing malformed JSON — e.g. trailing commas, truncated writes, or raw text output instead of JSON.

Common situations: User scripts writing partial/pretty-but-invalid JSON on crash; program output redirected straight to result.json; concurrent write truncated by job cancellation.

Related errors


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