{"record":{"id":"4b68179bdbe61bd2","repo":"can1357/oh-my-pi","slug":"embedded-addon-size-mismatch-for-filename-expe","errorCode":null,"errorMessage":"Embedded addon size mismatch for ${filename}: expected ${file.size}, got ${size}","messagePattern":"Embedded addon size mismatch for (.+?): expected (.+?), got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/natives/native/loader-state.js","lineNumber":536,"sourceCode":"\t\tconst size = readTarOctal(header, 124, 12);\n\t\tconst typeflag = header[156] === 0 ? \"0\" : String.fromCharCode(header[156]);\n\t\toffset += 512;\n\n\t\tif (offset + size > archive.length) {\n\t\t\tthrow new Error(`Truncated embedded addon archive entry: ${filename}`);\n\t\t}\n\n\t\tif (!isSafeEmbeddedAddonFilename(filename)) {\n\t\t\tthrow new Error(`Unsafe embedded addon archive entry: ${filename}`);\n\t\t}\n\t\tif (typeflag !== \"0\") {\n\t\t\tthrow new Error(`Unsupported embedded addon archive entry type ${typeflag}: ${filename}`);\n\t\t}\n\n\t\tconst file = pending.get(filename);\n\t\tif (file) {\n\t\t\tif (typeof file.size === \"number\" && file.size !== size) {\n\t\t\t\tthrow new Error(`Embedded addon size mismatch for ${filename}: expected ${file.size}, got ${size}`);\n\t\t\t}\n\t\t\tconst targetPath = path.join(targetDir, filename);\n\t\t\twriteEmbeddedAddonFile(targetPath, archive.subarray(offset, offset + size));\n\t\t\tpending.delete(filename);\n\t\t\twrittenPaths.push(targetPath);\n\t\t}\n\n\t\toffset += Math.ceil(size / 512) * 512;\n\t}\n\n\tif (pending.size > 0) {\n\t\tthrow new Error(`Embedded addon archive missing: ${[...pending.keys()].join(\", \")}`);\n\t}\n\n\treturn writtenPaths;\n}\n\nfunction maybeExtractEmbeddedAddon(ctx, errors) {","sourceCodeStart":518,"sourceCodeEnd":554,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/natives/native/loader-state.js#L518-L554","documentation":"The loader cross-checks each archive entry against the embedded manifest: when a pending manifest file declares a numeric size, the tar entry's actual size must match exactly. A mismatch means the archive bytes and the manifest metadata disagree, so writing the entry could produce a corrupt addon; the loader aborts.","triggerScenarios":"extractEmbeddedAddonArchive finds a pending entry (manifest said the on-disk file is missing or stale) whose tar header size differs from file.size in the manifest — e.g. manifest says 1048576 bytes but the tar entry holds 1048500.","commonSituations":"The embedded .tar.gz and the embedded manifest were generated from different build artifacts (partial/re-run build); the archive was repacked after the manifest was baked; byte-level corruption of the binary.","solutions":["Rebuild the compiled binary so the manifest and archive are regenerated together from the same artifacts.","Reinstall omp to replace the inconsistent embedded addon data.","If maintaining the packaging script, ensure the manifest's files[].size is computed from the exact bytes packed into the tar."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { execFileSync } from \"node:child_process\";\nfunction assertManifestSizesMatchArchive(archivePath, files) {\n  const listing = execFileSync(\"tar\", [\"-tvzf\", archivePath], { encoding: \"utf8\" });\n  const sizes = new Map(listing.split(\"\\n\").filter(Boolean).map(line => {\n    const parts = line.split(/\\s+/);\n    return [parts[parts.length - 1], Number(parts[2])];\n  }));\n  for (const f of files) {\n    if (typeof f.size === \"number\" && sizes.get(f.filename) !== f.size) {\n      throw new Error(`size mismatch for ${f.filename}`);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  extractEmbeddedAddonArchive({ archivePath, files, targetDir });\n} catch (err) {\n  if (err.message.includes(\"Embedded addon size mismatch for\")) {\n    // discard extracted files and force a clean reinstall/re-extract\n  } else throw err;\n}","preventionTips":["Generate files[].size from the exact bytes packed into the tar, in the same build step.","Never rebuild the archive without regenerating the manifest.","Verify sha256 of the packed artifact against the manifest in CI."],"tags":["integrity","size-mismatch","archive","native-addon"],"backgroundTag":"archive-checksum-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}