{"record":{"id":"485fcb6d5f7ff0a6","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-file-name-is-not-valid-utf-8","errorCode":null,"errorMessage":"Invalid CAB archive: file name is not valid UTF-8","messagePattern":"Invalid CAB archive: file name is not valid UTF-8","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":83,"sourceCode":"\t\toffset += 4;\n\t}\n\tconst remaining = bytes.byteLength - offset;\n\tlet remainder = 0;\n\tif (remaining === 3) {\n\t\tremainder = (bytes[offset]! << 16) | (bytes[offset + 1]! << 8) | bytes[offset + 2]!;\n\t} else if (remaining === 2) {\n\t\tremainder = (bytes[offset]! << 8) | bytes[offset + 1]!;\n\t} else if (remaining === 1) {\n\t\tremainder = bytes[offset]!;\n\t}\n\treturn (checksum ^ remainder) >>> 0;\n}\n\nfunction decodeName(bytes: Uint8Array, utf8: boolean): string {\n\ttry {\n\t\treturn utf8 ? UTF8_FATAL_DECODER.decode(bytes) : LEGACY_NAME_DECODER.decode(bytes);\n\t} catch {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: file name is not valid UTF-8\");\n\t}\n}\n\nfunction dosTimestamp(date: number, time: number): number | undefined {\n\tif (date === 0 && time === 0) return undefined;\n\tconst year = 1980 + (date >>> 9);\n\tconst month = (date >>> 5) & 0x0f;\n\tconst day = date & 0x1f;\n\tconst hour = time >>> 11;\n\tconst minute = (time >>> 5) & 0x3f;\n\tconst second = (time & 0x1f) * 2;\n\tif (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: file has an invalid DOS timestamp\");\n\t}\n\treturn new Date(year, month - 1, day, hour, minute, second).getTime();\n}\n\nfunction modeFromAttributes(attributes: number, directory: boolean): number {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L65-L101","documentation":"decodeName decodes a CFFILE entry's name using either a fatal UTF-8 decoder or a legacy decoder; if decoding is not lossless it throws this error rather than silently producing mojibake. Despite the fixed message mentioning UTF-8, this fires when the name bytes are invalid UTF-8 (utf8=true) or invalid in the legacy encoding (utf8=false). The library refuses archives whose entry names cannot be decoded cleanly.","triggerScenarios":"fileTable() iterating CFFILE entries whose szFile bytes are not valid UTF-8 when the CAB declares utf-8 naming, or not decodable in the legacy codepage fallback.","commonSituations":"CABs created by legacy Windows tools using codepage-encoded names (CP932/CP1251) that neither decode as UTF-8 nor as the configured legacy decoder; a hand-crafted or corrupted archive with random bytes in the name field; mixing archives built on different locale Windows machines.","solutions":["Re-create the CAB with UTF-8 file names (e.g. build on modern Windows or with libmspack-compatible tooling using ASCII/UTF-8 names).","If you control the source, rename entries to ASCII to sidestep codepage ambiguity.","Inspect the raw name bytes with a hex dump to identify the actual encoding, then re-encode the archive accordingly.","Patch/extend the legacy decoder (LEGACY_NAME_DECODER) with the correct TextDecoder label for the archive's origin codepage before decoding.","As a last resort, extract with cabextract (which handles codepage heuristics) and repackage."],"exampleFix":"// before: legacy JP codepage CAB fails decodeName\nawait readCabArchive(buffer); // Invalid CAB archive: file name is not valid UTF-8\n// after: repackage with UTF-8-safe names\n// $ cabextract old.cab && (cd old/ && find . -type f | LC_ALL=C.UTF-8 tar ... )\n// or rebuild: lcab --utf8 renamed-ascii-files/ new.cab","handlingStrategy":"validation","validationCode":"// Spot-check that the producer emits UTF-8-safe names before distributing the CAB\nconst names = listEntryNamesRaw(cabBytes); // your own raw-name extraction\nfor (const n of names) {\n  new TextDecoder('utf-8', { fatal: true }).decode(n); // throws if not UTF-8\n}","typeGuard":"function isValidUtf8(bytes: Uint8Array): boolean {\n  try { new TextDecoder('utf-8', { fatal: true }).decode(bytes); return true; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  return await readCabArchive(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('not valid UTF-8')) {\n    throw new Error('CAB entry names use a legacy codepage — re-create the archive with UTF-8 names');\n  }\n  throw err;\n}","preventionTips":["Standardize on ASCII or UTF-8 entry names when building CABs.","Know the locale/codepage of machines that produce your CABs.","Reject non-UTF-8 archives at ingestion rather than mid-extraction.","Document codepage requirements for archive producers in your pipeline."],"tags":["encoding","utf-8","archive","cab"],"backgroundTag":"invalid-utf8","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}