{"record":{"id":"d01b298f2fe97b97","repo":"denoland/deno","slug":"malformed-msi-no-columns-stream","errorCode":null,"errorMessage":"malformed .msi: no _Columns stream","messagePattern":"malformed \\.msi: no _Columns stream","errorType":"exception","errorClass":"AnyError","httpStatus":null,"severity":"error","filePath":"cli/tools/desktop.rs","lineNumber":5344,"sourceCode":"    (\"_Columns\", vec![str_w, 2, str_w, 2], vec![0, 1]),\n    (\n      \"_Validation\",\n      vec![str_w, str_w, str_w, 4, 4, str_w, 2, str_w, str_w, str_w],\n      vec![0, 1],\n    ),\n  ];\n  for (name, widths, keys) in system_tables {\n    if let Some(raw) = find_raw(name) {\n      let bytes = read_stream(&mut comp, &raw)?;\n      let sorted = msi_resort_stream(&bytes, widths, keys);\n      write_stream(&mut comp, &raw, &sorted)?;\n    }\n  }\n\n  // Parse the (now sorted) `_Columns` table to recover every persistent table's\n  // column widths and which columns are primary keys.\n  let columns_raw = find_raw(\"_Columns\").ok_or_else(|| {\n    deno_core::anyhow::anyhow!(\"malformed .msi: no _Columns stream\")\n  })?;\n  let columns = read_stream(&mut comp, &columns_raw)?;\n  let col_row_w = str_w + 2 + str_w + 2; // Table, Number, Name, Type\n  let ncol = columns.len() / col_row_w;\n  let read_col = |arr_off: usize, row: usize, w: usize| -> u64 {\n    let base = arr_off + row * w;\n    let mut v = 0u64;\n    for k in 0..w {\n      v |= (columns[base + k] as u64) << (8 * k);\n    }\n    v\n  };\n  let off_table = 0usize;\n  let off_number = ncol * str_w;\n  let off_type = off_number + ncol * 2 + ncol * str_w;\n  // A column Type word: 0x8000 marks the stored value present (always set here);\n  // 0x0800 marks a string type; 0x2000 marks a primary-key column; for integer\n  // columns the low byte is the storage size (2 or 4 bytes).","sourceCodeStart":5326,"sourceCodeEnd":5362,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/tools/desktop.rs#L5326-L5362","documentation":"The repacker sorts MSI system tables in place, then parses the _Columns table to recover each table's column widths and primary keys (needed to sort the remaining data tables). No _Columns stream means the database lacks its schema-definition table, so nothing downstream can be mapped — again a malformed-input signal, checked after the string streams were already found.","triggerScenarios":"find_raw(\"_Columns\") misses on a file that had _StringPool/_StringData: an MSI whose system tables were stripped or renamed by a prior tool, severe corruption, or an exotic authoring tool that omits it (standard ones never do).","commonSituations":"A previous repack/transform stripped system tables; the template passed through an optimizer that pruned streams; file corrupted in transfer or by antivirus quarantine.","solutions":["Start from a pristine template .msi from the original source; do not feed repacked output back as input.","Inspect streams with a compound-file viewer (7-Zip can list them) and confirm _Columns exists alongside the other _-prefixed tables.","If the pipeline intentionally strips tables, disable that step for the template used by the desktop installer build.","Quarantine-check the file (antivirus logs) if corruption has no obvious cause."],"exampleFix":"# before: repacked file fed back in as template\nmsi_repack out.msi out2.mi   # second pass over an already-repacked file\n# error: malformed .msi: no _Columns stream\n\n# after: always start from the pristine template\nmsi_repack template.msi out.msi","handlingStrategy":"validation","validationCode":"7z l template.msi | grep -q '_Columns' || { echo 'MSI schema stream missing — template was stripped or corrupted'; exit 1; }","typeGuard":null,"tryCatchPattern":"Catch and abort with a clear 'template unusable' message; a database without _Columns cannot be repacked and must be replaced from the pristine source, not retried.","preventionTips":["Do not run MSI optimizers/transformers over the template before the desktop repack.","Store the pristine template read-only so downstream steps cannot strip streams from it."],"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"}