zed-industries/zed · error

extension {} has invalid zed:api-version section: {:?}

Error message

extension {} has invalid zed:api-version section: {:?}

What it means

parse_wasm_extension_version() scans a compiled extension's .wasm for the 'zed:api-version' custom section, which Zed's extension builder writes as exactly 6 raw bytes: three big-endian u16s (major, minor, patch). parse_wasm_extension_version_custom_section() returns None unless data.len() == 6, so any other payload - a string like "1.0.0", an empty section, truncated bytes - triggers this bail. The section is Zed's embedded record of which Extension API version the wasm was built against.

Source

Thrown at crates/extension/src/extension.rs:201

    ) -> Result<Option<DebugScenario>>;
    async fn run_dap_locator(
        &self,
        locator_name: String,
        config: SpawnInTerminal,
    ) -> Result<DebugRequest>;
}

pub fn parse_wasm_extension_version(extension_id: &str, wasm_bytes: &[u8]) -> Result<Version> {
    let mut version = None;

    for part in wasmparser::Parser::new(0).parse_all(wasm_bytes) {
        if let wasmparser::Payload::CustomSection(s) =
            part.context("error parsing wasm extension")?
            && s.name() == "zed:api-version"
        {
            version = parse_wasm_extension_version_custom_section(s.data());
            if version.is_none() {
                bail!(
                    "extension {} has invalid zed:api-version section: {:?}",
                    extension_id,
                    s.data()
                );
            }
        }
    }

    // The reason we wait until we're done parsing all of the Wasm bytes to return the version
    // is to work around a panic that can happen inside of Wasmtime when the bytes are invalid.
    //
    // By parsing the entirety of the Wasm bytes before we return, we're able to detect this problem
    // earlier as an `Err` rather than as a panic.
    version.with_context(|| format!("extension {extension_id} has no zed:api-version section"))
}

fn parse_wasm_extension_version_custom_section(data: &[u8]) -> Option<Version> {
    if data.len() == 6 {

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Rebuild the extension with the current toolchain: 'zed extension build' (or crates/extension extension_builder), which writes the correct 6-byte section
  2. If you emit the section yourself, write exactly 6 bytes: major, minor, patch as big-endian u16 each (e.g. version 0.6.0 -> [0x00,0x00, 0x00,0x06, 0x00,0x00])
  3. Avoid wasm post-processing steps that drop custom sections (check wasm-opt/wasm-strip flags), or re-add the section afterwards
  4. If the file was hand-modified or downloaded, recompile from source to eliminate corruption

Example fix

// before: writing the version as a string
section.data = b"0.6.0"; // len 5 -> 'invalid zed:api-version section'

// after: exactly 6 bytes, three big-endian u16s
let (major, minor, patch) = (0u16, 6u16, 0u16);
let mut data = Vec::new();
for part in [major, minor, patch] {
    data.extend_from_slice(&part.to_be_bytes());
}
section.data = &data; // len 6 -> parses to Version::new(0, 6, 0)
Defensive patterns

Strategy: validation

Validate before calling

// Verify the section length before handing the wasm to Zed
fn has_valid_api_version(wasm_bytes: &[u8]) -> bool {
    for part in wasmparser::Parser::new(0).parse_all(wasm_bytes).flatten() {
        if let wasmparser::Payload::CustomSection(s) = part
            && s.name() == "zed:api-version"
        {
            return s.data().len() == 6;
        }
    }
    false
}

Try / catch

match parse_wasm_extension_version(extension_id, &wasm_bytes) {
    Ok(version) => Some(version),
    Err(err) if err.to_string().contains("invalid zed:api-version") => {
        log::warn!("skipping malformed extension {extension_id}: {err:#}");
        None
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Loading or analyzing a Zed wasm extension whose zed:api-version custom section is not 6 bytes: wasm built by an outdated/foreign toolchain that wrote a different format (e.g. semver string or JSON), a hand-written build script that adds the custom section itself, or a corrupted/truncated .wasm file.

Common situations: Extension authors adding the section manually with a string version instead of binary u16 triples; wasm rebuilt or post-processed (wasm-opt/wasm-tools strip or rewrite custom sections); extensions compiled by mismatched Zed versions whose section format differed.

Related errors


AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20). Data as JSON: /api/errors/6f5d97569a532d66. Report an issue: GitHub.