{"record":{"id":"8a028ec075927898","repo":"denoland/deno","slug":"malformed-msi-no-stringdata-stream","errorCode":null,"errorMessage":"malformed .msi: no _StringData stream","messagePattern":"malformed \\.msi: no _StringData stream","errorType":"exception","errorClass":"AnyError","httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":5303,"sourceCode":"      .cloned()\n  };\n\n  // The string-pool header's top bit selects 3-byte string references; tiny\n  // databases use 2-byte refs, but honor the flag to stay correct at any size.\n  let pool_raw = find_raw(\"_StringPool\").ok_or_else(|| {\n    deno_core::anyhow::anyhow!(\"malformed .msi: no _StringPool stream\")\n  })?;\n  let pool = read_stream(&mut comp, &pool_raw)?;\n  let str_w: usize = if pool.len() >= 4 && (pool[3] & 0x80) != 0 {\n    3\n  } else {\n    2\n  };\n\n  // Map every string-pool id to its text so data-table streams (named by table\n  // text) can be matched to their column schema (keyed by table string id).\n  let data_raw = find_raw(\"_StringData\").ok_or_else(|| {\n    deno_core::anyhow::anyhow!(\"malformed .msi: no _StringData stream\")\n  })?;\n  let str_data = read_stream(&mut comp, &data_raw)?;\n  let mut strings = vec![String::new()]; // 1-based; index 0 is unused.\n  {\n    let mut off = 0usize;\n    let mut i = 4;\n    while i + 4 <= pool.len() {\n      let len = u16::from_le_bytes([pool[i], pool[i + 1]]) as usize;\n      let end = (off + len).min(str_data.len());\n      strings.push(String::from_utf8_lossy(&str_data[off..end]).into_owned());\n      off += len;\n      i += 4;\n    }\n  }\n  let id_of = |text: &str| -> Option<u64> {\n    strings.iter().position(|s| s == text).map(|i| i as u64)\n  };\n","sourceCodeStart":5285,"sourceCodeEnd":5321,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L5285-L5321","documentation":"Companion check to the _StringPool error: after locating the string-pool header stream, the repacker needs the _StringData stream (the concatenated UTF-8 string bytes the pool indexes into). Its absence with the same find_raw/de-mangle lookup means the MSI's string table is half-present — effectively a malformed or non-MSI input, since every valid MSI writes both streams together.","triggerScenarios":"find_raw(\"_StringData\") misses after _StringPool was found: a truncated compound file where later streams were cut off, a hand-crafted/corrupted database, or stream-name mangling that only some names survive.","commonSituations":"Truncated template download (pool near the start survived, data stream at the end did not); disk-full while the template was written; a partial copy from an artefact store.","solutions":["Verify integrity of the template: compare its size/SHA-256 against the known-good source, re-download it.","Open the file with lessmsi/msidb to confirm both string-table streams are present before repacking.","If building the template in-house, ensure the MSI authoring tool completed successfully (check its exit status and logs)."],"exampleFix":"# before: template truncated by an interrupted download\nls -l template.msi          # 41 KB (expected ~3 MB)\n# error: malformed .msi: no _StringData stream\n\n# after: refetch and verify\nsha256sum template.msi      # match against known-good digest, then rebuild","handlingStrategy":"validation","validationCode":"7z l template.msi | grep -q '_StringData' || { echo 'MSI string data stream missing — template truncated/corrupt'; exit 1; }\nsha256sum template.msi   # compare against the digest recorded when the template was first obtained","typeGuard":null,"tryCatchPattern":"Treat like 1795: catch, verify the template digest against its known-good value, and abort the build on mismatch; do not attempt partial recovery of a half-present string table.","preventionTips":["Pin and verify template digests in CI so truncated downloads are caught before repacking.","Ensure template downloads are atomic (download to temp, checksum, then move into place)."],"tags":["windows","msi","installer","file-format","validation"],"backgroundTag":"msi-validation-failed","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}