{"record":{"id":"6175b0b028f216eb","repo":"TeamNewPipe/NewPipe","slug":"parser-go-beyond-limits-of-the-box-type-s-offset","errorCode":null,"errorMessage":"parser go beyond limits of the box. type=%s offset=%s size=%s position=%s","messagePattern":"parser go beyond limits of the box\\. type=(.+?) offset=(.+?) size=(.+?) position=(.+?)","errorType":"exception","errorClass":"EOFException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/org/schabi/newpipe/streams/Mp4DashReader.java","lineNumber":311,"sourceCode":"        buffer.putInt(ref.type);\n\n        final int read = size - 8;\n\n        if (stream.read(buffer.array(), 8, read) != read) {\n            throw new EOFException(String.format(\"EOF reached in box: type=%s offset=%s size=%s\",\n                    boxName(ref.type), ref.offset, ref.size));\n        }\n\n        return buffer.array();\n    }\n\n    private void ensure(final Box ref) throws IOException {\n        final long skip = ref.offset + ref.size - stream.position();\n\n        if (skip == 0) {\n            return;\n        } else if (skip < 0) {\n            throw new EOFException(String.format(\n                    \"parser go beyond limits of the box. type=%s offset=%s size=%s position=%s\",\n                    boxName(ref), ref.offset, ref.size, stream.position()\n            ));\n        }\n\n        stream.skipBytes((int) skip);\n    }\n\n    private Box untilBox(final Box ref, final int... expected) throws IOException {\n        Box b;\n        while (stream.position() < (ref.offset + ref.size)) {\n            b = readBox();\n            for (final int type : expected) {\n                if (b.type == type) {\n                    return b;\n                }\n            }\n            ensure(b);","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/TeamNewPipe/NewPipe/blob/9e8be091560a69f35d44bd252eb00bc7911c977b/app/src/main/java/org/schabi/newpipe/streams/Mp4DashReader.java#L293-L329","documentation":"Mp4DashReader.ensure(ref) computes how many bytes remain until the end of the current box (ref.offset + ref.size - stream.position()). A negative skip means the parser already read PAST the declared box boundary — the sub-parser consumed more bytes than the box allows, indicating a corrupt or inconsistent box. The EOFException reports type/offset/size/position for diagnosis.","triggerScenarios":"Any ensure(ref) call after parsing box children where a sub-parser read beyond the parent box's declared size. The parent box size is smaller than the sum of its children, or a child's declared length overran the parent.","commonSituations":"A malformed box with an undersized size field relative to its content; a corrupted trun/stbl/traf where field lengths are inconsistent; a tampered file; a muxer bug producing inconsistent nested sizes.","solutions":["Re-download or re-mux the file; nested box sizes are internally inconsistent.","Validate with MP4Box/mp4info which also reports size inconsistencies.","If you produce the files, audit nested box size computation to ensure children never exceed parent extents.","Treat the error as fatal for the fragment and skip to the next moof if resilience is required."],"exampleFix":"// before — sub-parser can overrun the parent box and trigger ensure()\nparseChildren(box); // reads past box.size\n\n// after — clamp child reads to the parent box boundary\nlong limit = box.offset + box.size;\nwhile (stream.position() < limit) { parseChild(box); }","handlingStrategy":"validation","validationCode":"// Producer-side: ensure sub-parsers never read past the parent box boundary.\nlong parentEnd = box.offset + box.size;\nwhile (stream.position() < parentEnd) {\n    parseChild(box, parentEnd); // pass limit, clamp child reads\n}","typeGuard":"public static boolean childWithinParent(long childEnd, long parentEnd) {\n    return childEnd <= parentEnd;\n}","tryCatchPattern":"try {\n    ensure(box);\n} catch (EOFException e) {\n    if (e.getMessage().contains(\"beyond limits\")) {\n        // parser overran the box — fragment is corrupt, skip to next moof\n        Log.w(TAG, \"box overrun at \" + e.getMessage());\n        continue;\n    } else throw e;\n}","preventionTips":["Re-mux corrupt files with a conformant tool.","Validate nested box sizes with MP4Box -info.","When implementing sub-parsers, clamp reads to the parent box extent.","Treat overruns as fatal for the current fragment only."],"tags":["mp4","container","corrupt-data","offset-validation","java"],"backgroundTag":null,"analyzedSha":"9e8be091560a69f35d44bd252eb00bc7911c977b","analyzedAt":"2026-08-14T00:11:33.519Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}