{"slug": "the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a", "title": "The Video That Played Everywhere Except on Phones: A Codec Bug Hiding Behind a Healthy Server.", "summary": "A solo developer of the AI video editing SaaS snipforge.video fixed a bug where shared videos showed 0:00 and refused to play on iPhones. The root cause was a VP9 codec inside an MP4 container, which Safari does not support, and a parser bug that failed to detect it due to ffprobe's field order. The fix involved re-encoding to H.264/AAC when needed.", "body_md": "*This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.*\n\nI run [snipforge.video](https://snipforge.video), an AI video editing SaaS, solo. One of its core features is share links: process a video, get a URL, send it to someone. A user reported that a shared video showed 0:00 and refused to play on their iPhone. I opened the same link on desktop Chrome and it played perfectly. Classic \"works on my machine,\" except my machine was every desktop and the failure was every iPhone.\n\nThis is the worst kind of bug report for a solo founder, because the person hitting it is usually not your user. It is the person your user shared the video with. They do not file a bug. They just conclude your product is broken and close the tab.\n\nEverything about the symptom pointed at the serving path, so that is where I went first. Shared files live on Cloudflare R2 behind the app, and mobile Safari is famously picky about how video is served, so I had a lineup of plausible suspects:\n\n`faststart`\n\nmakes Safari wait for metadata that lives at the end of the fileI checked each one. Range requests: honored, correct 206 responses with proper `Content-Range`\n\n. Faststart: moov atom at the front, verified. Headers: `video/mp4`\n\n, correct. Every infrastructure suspect had an alibi. The serving path was completely healthy, which was somehow worse news, because now the file itself was the suspect and the file was \"an MP4 that plays fine.\"\n\n`ffprobe`\n\non the shared file settled it in one line. The container was MP4, but the video stream inside it was VP9. Desktop Chrome plays VP9 in an MP4 wrapper without complaint. iPhone Safari does not, and it fails the way Safari loves to fail: no error, no console message, just a player showing 0:00 forever.\n\nThe file extension said .mp4, the Content-Type said video/mp4, and both were telling the truth about the container while saying nothing about the codec. Every layer of the stack was technically honest and the sum was a lie.\n\nThe fix belonged in the share pipeline's web-optimize step: probe the actual codecs, and if the video is not H.264 or the audio is not AAC, re-encode to the one combination that plays everywhere, instead of trusting the container.\n\nHere is the part I am actually writing this post for.\n\nMy first patch probed the streams with ffprobe's CSV output, something shaped like this:\n\n```\nffprobe -v error -show_entries stream=codec_type,codec_name -of csv=p=0 input.mp4\n```\n\nI wrote the parser assuming each line came back as `codec_type,codec_name`\n\n, so `video,vp9`\n\n. Deployed it, re-shared the test video, still 0:00 on the iPhone.\n\nThe re-encode condition never fired, because ffprobe prints the fields in its own fixed order, not the order you listed them in `-show_entries`\n\n. The actual output was `vp9,video`\n\n. My parser was comparing the codec name against the string \"video\", the match always failed, the code concluded every file was fine, and the function returned the original untouched file. No exception, no log noise, a clean deploy, and zero effect.\n\nA fix that runs successfully and does nothing is more dangerous than a fix that crashes, because a crash tells you where to look. This one told me nothing, and for a little while I went back to re-suspecting the innocent serving path.\n\nPrinting the raw ffprobe output side by side with what my parser thought it saw ended the mystery in about thirty seconds. The lesson was old and evergreen: when parsing tool output, log the raw input next to the parsed result, because your mental model of the format is a hypothesis, not a fact.\n\nWith the parser reading fields in the right order, the probe correctly flagged VP9, the pipeline re-encoded to H.264/AAC with faststart, and the same share link played on the same iPhone immediately.\n\nThe durable wins:\n\nNot the fix itself, which is twenty lines. It is that the debugging held discipline when the evidence was contradictory: the server was provably healthy AND the file provably did not play. Instead of picking a side and flailing, following the contradiction down one more layer found the third option nobody was accusing, the codec inside a truthful container.\n\nAlso, mild pride in having personally shipped, broken, and re-shipped the fix within the same day, which is the full solo founder experience in miniature.", "url": "https://wpnews.pro/news/the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a", "canonical_source": "https://dev.to/snipforge/the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a-healthy-server-4aff", "published_at": "2026-08-15 05:07:05+00:00", "updated_at": "2026-08-15 05:41:01.927486+00:00", "lang": "en", "topics": ["ai-products", "developer-tools"], "entities": ["snipforge.video", "Cloudflare R2", "Safari", "Chrome", "ffprobe", "VP9", "H.264", "AAC"], "alternates": {"html": "https://wpnews.pro/news/the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a", "markdown": "https://wpnews.pro/news/the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a.md", "text": "https://wpnews.pro/news/the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a.txt", "jsonld": "https://wpnews.pro/news/the-video-that-played-everywhere-except-on-phones-a-codec-bug-hiding-behind-a.jsonld"}}