{"record":{"id":"0271519999e9dcb5","repo":"yuliskov/SmartTube","slug":"malformed-mpd-file-mpdcontent","errorCode":null,"errorMessage":"Malformed mpd file:\n${mpdContent}","messagePattern":"Malformed mpd file:\n(.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/liskovsoft/smartyoutubetv2/common/exoplayer/ExoMediaSourceFactory.java","lineNumber":260,"sourceCode":"    }\r\n\r\n    private SabrManifest getSabrManifest(MediaItemFormatInfo formatInfo) {\r\n        SabrManifestParser parser = new SabrManifestParser();\r\n        return parser.parse(formatInfo);\r\n    }\r\n\r\n    private DashManifest getManifest(MediaItemFormatInfo formatInfo) {\r\n        DashManifestParser2 parser = new DashManifestParser2();\r\n        return parser.parse(formatInfo);\r\n    }\r\n\r\n    private DashManifest getManifest(Uri uri, InputStream mpdContent) {\r\n        DashManifestParser parser = new StaticDashManifestParser();\r\n        DashManifest result;\r\n        try {\r\n            result = parser.parse(uri, mpdContent);\r\n        } catch (IOException e) {\r\n            throw new IllegalStateException(\"Malformed mpd file:\\n\" + mpdContent, e);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    private DashManifest getManifest(Uri uri, String mpdContent) {\r\n        DashManifestParser parser = new StaticDashManifestParser();\r\n        DashManifest result;\r\n        try {\r\n            result = parser.parse(uri, FileHelpers.toStream(mpdContent));\r\n        } catch (IOException e) {\r\n            throw new IllegalStateException(\"Malformed mpd file:\\n\" + mpdContent, e);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Use OkHttp for networking\r\n     */\r","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/yuliskov/SmartTube/blob/3de8d90593e0166f012ca18cc3c7ba45bfd68ac4/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/exoplayer/ExoMediaSourceFactory.java#L242-L278","documentation":"getManifest(Uri, InputStream) parses already-fetched mpd bytes with StaticDashManifestParser; an IOException from the parser (malformed XML, empty or truncated body) is rethrown as IllegalStateException embedding the entire mpd content for diagnosis. When the 'mpd' is actually an HTML error page, the exception text makes that obvious — which is the point of including it.","triggerScenarios":"The fetched URL returned an HTML error/block page instead of DASH xml (expired signed URL, geo-block, proxy interference); the body was truncated mid-transfer; the InputStream is empty because the upstream fetch already failed.","commonSituations":"Expired stream URLs from YouTube-style backends; VPN/ISP-injected pages; ad-blocking or AFR proxy rewriting responses; retrying playback with stale cached format info.","solutions":["Read the embedded content prefix in the exception message — '<MPD' vs '<html' distinguishes a parser bug from a bad response","Re-fetch the format info / refresh the URL and rebuild the media source before retrying","If the body is HTML, investigate middleboxes (proxy, VPN, DNS filtering) rather than the parser","Treat it as a parser defect only when the content is well-formed mpd and still fails"],"exampleFix":"// before\nDashManifest m = parser.parse(uri, mpdStream); // IOException -> IllegalStateException\n\n// after\nif (mpdContent == null || !mpdContent.trim().startsWith(\"<\")) {\n    throw new IllegalStateException(\"URL did not return a manifest (likely an error page)\");\n}\nDashManifest m = parser.parse(uri, FileHelpers.toStream(mpdContent));","handlingStrategy":"validation","validationCode":"String body = readFully(stream);\nif (body == null || !body.trim().startsWith(\"<\")) {\n    // not a manifest: refresh the url / format info instead of parsing\n    return refreshAndRetry();\n}\nDashManifest manifest = parser.parse(uri, FileHelpers.toStream(body));","typeGuard":null,"tryCatchPattern":"try {\n    return getManifest(uri, stream);\n} catch (IllegalStateException e) {\n    // message embeds the body: inspect prefix, then re-fetch manifest and retry once\n}","preventionTips":["Sanity-check that fetched manifest bodies start with '<MPD' before parsing","Refresh signed/expiring URLs before building a media source from cached content","Treat HTML bodies as a network/middlebox signal, not a parser defect"],"tags":["exoplayer","dash","mpd","manifest","streaming"],"backgroundTag":"malformed-dash-manifest","analyzedSha":"3de8d90593e0166f012ca18cc3c7ba45bfd68ac4","analyzedAt":"2026-08-22T09:19:26.383Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}