{"record":{"id":"86c11b6d9baf7bf4","repo":"vercel-labs/skills","slug":"invalid-tar-entry-size","errorCode":null,"errorMessage":"Invalid tar entry size","messagePattern":"Invalid tar entry size","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/providers/wellknown.ts","lineNumber":733,"sourceCode":"\n  private extractTarGz(bytes: Uint8Array): Map<string, WellKnownFileContent> {\n    const tar = gunzipSync(Buffer.from(bytes));\n    const files = new Map<string, WellKnownFileContent>();\n    const runningTotal = { bytes: 0 };\n    let offset = 0;\n\n    while (offset + 512 <= tar.length) {\n      const header = tar.subarray(offset, offset + 512);\n      if (header.every((byte) => byte === 0)) break;\n\n      const name = this.readTarString(header, 0, 100);\n      const sizeText = this.readTarString(header, 124, 12).trim();\n      const typeFlag = header[156];\n      const prefix = this.readTarString(header, 345, 155);\n      const path = prefix ? `${prefix}/${name}` : name;\n      const size = Number.parseInt(sizeText || '0', 8);\n\n      if (!Number.isFinite(size) || size < 0) throw new Error('Invalid tar entry size');\n      offset += 512;\n\n      // Reject symlinks and hard links. Skip directories and metadata entries.\n      if (typeFlag === 0x32 || typeFlag === 0x31) {\n        throw new Error('Archive links are not supported');\n      }\n\n      const isFile = typeFlag === 0 || typeFlag === 0x30;\n      if (isFile) {\n        const content = tar.subarray(offset, offset + size);\n        this.addArchiveFile(files, path, new Uint8Array(content), runningTotal);\n      }\n\n      offset += Math.ceil(size / 512) * 512;\n    }\n\n    if (!files.has('SKILL.md')) throw new Error('Archive missing root SKILL.md');\n    return files;","sourceCodeStart":715,"sourceCodeEnd":751,"githubUrl":"https://github.com/vercel-labs/skills/blob/435076e78988e1e6ec40d00b0b1d76bdbbc5419a/src/providers/wellknown.ts#L715-L751","documentation":"While parsing a tar header, the octal size field at offset 124 is read and parsed; if it is not a finite non-negative number the entry is malformed and 'Invalid tar entry size' is thrown, aborting extraction.","triggerScenarios":"A corrupt or non-tar payload reaching extractTarGz: truncated downloads, gzip bombs that decode to garbage, tar headers with binary/GNU base-256 sizes the parser mishandles, or off-alignment after a previous bad entry.","commonSituations":"Interrupted downloads stored by a CDN; registry serving an HTML error page gzip-compressed; crafted archives designed to break naive tar parsers.","solutions":["Re-download the artifact and verify its integrity (checksum, gzip -t file.tar.gz)","Confirm the artifact URL serves a real tar.gz (curl -sI and inspect Content-Type/Length)","Re-publish a well-formed archive built with standard GNU/bsdtar","Report registry-side corruption if it reproduces consistently"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { gzipSync, gunzipSync } from 'node:zlib';\nfunction looksLikeTarGz(buf: Buffer): boolean {\n  try {\n    const t = gunzipSync(buf);\n    return t.length >= 512 && t.toString('utf8', 257, 262) === 'ustar';\n  } catch { return false; }\n}\nif (!looksLikeTarGz(bytes)) throw new Error('payload is not a valid tar.gz');","typeGuard":"function isInvalidTarEntry(e: unknown): e is Error {\n  return e instanceof Error && /Invalid tar entry size/.test(e.message);\n}","tryCatchPattern":"try { await provider.fetchArtifact(url); }\ncatch (e) {\n  if (isInvalidTarEntry(e)) {\n    cache.bust(url); // cached corrupt copy likely\n    return await provider.fetchArtifact(url); // single re-fetch\n  }\n  throw e;\n}","preventionTips":["Verify artifact checksums when publishing/consuming","Treat corrupt-archive errors as cache-busting events, not permanent failures","Validate gzip magic bytes (1f 8b) before parsing"],"tags":["archive","tar","corruption","parsing","wellknown-provider"],"backgroundTag":"corrupt-archive-parsing","analyzedSha":"435076e78988e1e6ec40d00b0b1d76bdbbc5419a","analyzedAt":"2026-08-28T17:47:53.369Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}