{"record":{"id":"9d1ed2bdda8f2316","repo":"remotion-dev/remotion","slug":"invalid-table-id-tableid","errorCode":null,"errorMessage":"Invalid table ID: ${tableId}","messagePattern":"Invalid table ID: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/transport-stream/parse-pat.ts","lineNumber":24,"sourceCode":"\nexport type TransportStreamProgramAssociationTableEntry = {\n\ttype: 'transport-stream-program-association-table';\n\tprogramNumber: number;\n\tprogramMapIdentifier: number;\n};\n\nconst parsePatTable = (\n\titerator: BufferIterator,\n\ttableId: number,\n): TransportStreamPATBox => {\n\titerator.getUint16(); // table ID extension\n\titerator.startReadingBits();\n\titerator.getBits(7); // reserved\n\titerator.getBits(1); // current / next indicator;\n\tconst sectionNumber = iterator.getBits(8);\n\tconst lastSectionNumber = iterator.getBits(8);\n\tif (tableId !== 0) {\n\t\tthrow new Error('Invalid table ID: ' + tableId);\n\t}\n\n\tconst tables: TransportStreamProgramAssociationTableEntry[] = [];\n\tfor (let i = sectionNumber; i <= lastSectionNumber; i++) {\n\t\tconst programNumber = iterator.getBits(16); // program number\n\t\titerator.getBits(3); // reserved\n\t\tconst programMapIdentifier = iterator.getBits(13); // program map PID\n\n\t\ttables.push({\n\t\t\ttype: 'transport-stream-program-association-table',\n\t\t\tprogramNumber,\n\t\t\tprogramMapIdentifier,\n\t\t});\n\t}\n\n\titerator.stopReadingBits();\n\n\treturn {","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/transport-stream/parse-pat.ts#L6-L42","documentation":"Thrown by parsePatTable when the PAT (Program Association Table) table_id field is not 0x00. Per ISO/IEC 13818-1, the PAT is identified exclusively by table_id = 0; any other value means the buffer does not actually contain a PAT. The library uses this guard to ensure parsePat is consuming the right packet before reading program associations.","triggerScenarios":"parsePat() reads the first byte as tableId and forwards it to parsePatTable, which throws at parse-pat.ts:24 when tableId !== 0. Triggered when the parser routes a non-PAT packet (e.g. PMT table_id=2, SDT table_id=0x42) into parsePat, or when the MPEG-TS bitstream is corrupted so the leading byte of the section is not 0x00.","commonSituations":"Corrupt or truncated MPEG-TS files where the PAT packet payload is damaged; mis-demultiplexed .ts streams; files produced by broken encoders that write the wrong table_id; partial downloads where the PAT packet starts mid-payload.","solutions":["Re-mux or re-record the source .ts file with a conformant encoder (ffmpeg: ffmpeg -i in.ts -c copy -mpegts_pmt_version 0 out.ts).","Verify the file with a reference tool such as ffprobe/mediainfo to confirm the PAT table_id is 0.","If the file is intentionally non-standard, preprocess it (ffmpeg -i in.ts -map 0 -c copy out.ts) to normalize tables before feeding it to @remotion/media-parser.","Handle the failure at the call site by treating the stream as unparseable and falling back to a different container or demuxer."],"exampleFix":"// before\nawait parseMedia({src: corruptedUrl, fields: {dimensions: true}});\n\n// after - validate file with ffprobe first, then fall back\ntry {\n  await parseMedia({src, fields: {dimensions: true}});\n} catch (e) {\n  if (e.message === 'Invalid table ID: ' + someId) {\n    // re-encode a clean copy\n    await transcodeWithFfmpeg(src, cleanSrc);\n    await parseMedia({src: cleanSrc, fields: {dimensions: true}});\n  } else throw e;\n}","handlingStrategy":"validation","validationCode":"// Pre-check a .ts file before handing it to parseMedia by demuxing with ffprobe\nimport {execSync} from 'node:child_process';\nfunction hasValidPat(src: string): boolean {\n  try {\n    const out = execSync(`ffprobe -v error -show_streams -of json \"${src}\"`).toString();\n    const json = JSON.parse(out);\n    return Array.isArray(json.streams) && json.streams.length > 0;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await parseMedia({src, fields: {durationInSeconds: true}});\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Invalid table ID')) {\n    // corrupt PAT - re-encode and retry once\n    await transcode(src, src + '.remux.ts');\n    await parseMedia({src: src + '.remux.ts', fields: {durationInSeconds: true}});\n  } else throw e;\n}","preventionTips":["Pre-validate transport-stream inputs with ffprobe before parsing.","Re-mux untrusted .ts files with ffmpeg before processing.","Wrap parseMedia in a try/catch that distinguishes corruption from unsupported-format errors."],"tags":["media-parser","transport-stream","mpegts","validation","container-format"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}