denoland/deno · error

Failed to parse profile: {}

Error message

Failed to parse profile: {}

What it means

When the CPU profiler writes its report (enabled via the `--cpu-profiler` + markdown-report option in runtime/cpu_profiler), `generate_markdown_report` deserializes the V8 CPU profile JSON into the strict `CpuProfile` struct (nodes, samples, timeDeltas, startTime/endTime, ...). If serde rejects the value, the error is wrapped into `std::io::Error` with kind `InvalidData` and this message including the serde detail. The raw `.cpuprofile` file has already been written; only the `.md` report fails, and runtime/cpu_profiler/mod.rs logs the error and continues.

Source

Thrown at runtime/cpu_profiler/cpuprof.rs:67

struct FunctionStats {
  function_name: String,
  url: String,
  line_number: i32,
  self_time: i64,
  total_time: i64,
  self_samples: i32,
  total_samples: i32,
}

pub(crate) fn generate_markdown_report(
  profile: &serde_json::Value,
  filepath: &std::path::Path,
  interval_us: i64,
) -> std::io::Result<()> {
  let profile: CpuProfile = match serde_json::from_value(profile.clone()) {
    Ok(p) => p,
    Err(err) => {
      return Err(std::io::Error::new(
        std::io::ErrorKind::InvalidData,
        format!("Failed to parse profile: {}", err),
      ));
    }
  };

  let mut md = String::new();

  // Calculate stats
  let duration_us = profile.end_time - profile.start_time;
  let duration_ms = duration_us as f64 / 1000.0;
  let total_samples = profile.samples.len();
  let total_functions = profile.nodes.len();

  // Build node map
  let node_map: HashMap<i32, &ProfileNode> =
    profile.nodes.iter().map(|n| (n.id, n)).collect();

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Check the appended serde error (`Failed to parse profile: {err}`) — it names the exact field and reason that failed to deserialize.
  2. Align the `CpuProfile` struct fields in runtime/cpu_profiler/cpuprof.rs with the actual JSON (add `#[serde(default)]` for newly optional fields or map renamed keys with `#[serde(rename = "...")]`).
  3. If the format changed with a V8 upgrade, update the deserialization for the new format rather than skipping the report.
  4. The `.cpuprofile` itself is still valid — as a workaround, open it directly in Chrome DevTools > Performance or speedscope until the report generator is fixed.

Example fix

// before (runtime/cpu_profiler/cpuprof.rs)
#[derive(Deserialize)]
pub(crate) struct CpuProfile {
  pub nodes: Vec<ProfileNode>,
  pub samples: Vec<i32>,
  pub time_deltas: Vec<i32>,
  // ...
}

// after — tolerate fields V8 makes optional
#[derive(Deserialize)]
pub(crate) struct CpuProfile {
  #[serde(default)]
  pub nodes: Vec<ProfileNode>,
  #[serde(default)]
  pub samples: Vec<i32>,
  #[serde(default)]
  pub time_deltas: Vec<i32>,
  // ...
}
Defensive patterns

Strategy: try-catch

Validate before calling

// If you call generate_markdown_report on an arbitrary profile value,
// pre-check the shape before deserializing:
fn looks_like_cpuprofile(v: &serde_json::Value) -> bool {
  v.get("nodes").map(|n| n.is_array()).unwrap_or(false)
    && v.get("samples").map(|n| n.is_array()).unwrap_or(false)
    && v.get("startTime").map(|n| n.is_i64()).unwrap_or(false)
    && v.get("endTime").map(|n| n.is_i64()).unwrap_or(false)
}

Try / catch

// Mirror runtime/cpu_profiler/mod.rs: treat report generation as best-effort —
// the .cpuprofile file is already flushed; log and continue on InvalidData.
if let Err(err) = cpuprof::generate_markdown_report(&profile, &md_path, interval) {
  if err.kind() == std::io::ErrorKind::InvalidData {
    log::error!("profile shape rejected, raw .cpuprofile remains usable: {err}");
  } else {
    log::error!("report write failed: {err}");
  }
}

Prevention

When it happens

Trigger: Running with the CPU profiler and markdown-report generation enabled where the profile JSON does not match the `CpuProfile` schema: missing keys (e.g. no `timeDeltas`), wrong value types, or extra-incompatible shapes after a V8 version bumps the profile format (e.g. new node fields or changed sample encoding).

Common situations: Upgrading V8/deno_core where the `.cpuprofile` format evolved; a profile with zero samples producing surprising shapes; feeding a hand-edited or external (Chrome DevTools-style, different version) profile file into the report generator.

Understand the failure class

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/86d929a4e5838515. Report an issue: GitHub.