Your “problem” is related to the length and size of the video. I don’t know how the default buffer used by Chrome is used (this may depend on several things, such as free memory, free disk space, etc.), but you should not rely on it to play your video!
One of your videos is few seconds smaller and almost a third more than the other. Chrome fully loads the smaller video (probably in memory), but doesn't do the same with the other. And since it is larger than the buffer, it needs a server to support range requests (partial content maintenance). As you serve the content of your video, you do not support the partial provision of content (which Chrome expects in the case of "large" videos), so Chrome simply refuses to process / play the video.
You must serve your files using http.ServeFile() , which supports Range range requests (required for videos that are larger than a certain size). See Related Question: How do I serve HTTP partial content with Go?
Once you do this, both of your video files will play normally.
Going further, there is no practical reason not to use http.ServeFile() . It will not load the complete file into memory, as you did, which is a very bad idea in the case of large (video) files. http.ServeFile() processes range requests, if specified, and also correctly sets response headers, including the Content-Type (and knows that a .mp4 file requires a video/mp4 MIME type).
Analysis of large video file requests
Testing this simple application:
func fileh(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "/path/to/a/big/video.mp4") } func main() { http.HandleFunc("/", fileh) panic(http.ListenAndServe("localhost:8080", nil)) }
And opening http://localhost:8080 from Chrome, the browser makes 2 requests (I intentionally filtered out non-essential / unrelated request-response headers):
Request No. 1
GET / HTTP/1.1
To get the requested (root) path.
Answer # 1
HTTP/1.1 200 OK Accept-Ranges: bytes Content-Length: 104715956 Content-Type: video/mp4
As you can see, the Go app reports that the video is about 100 MB in size. http.ServeFile() also includes an Accept-Ranges: bytes response header, which lets clients know that we support range requests.
How does Chrome react to this? Closes the connection after receiving 32 KB (32.2 KB, including headers, which is enough to look into the stream and say what it can do with it), then starts another request (which also happens even if the Accept-Ranges response header is not sent - your sample code does not send):
Request No. 2
GET / HTTP/1.1 Referer: http://localhost:8080/ Range: bytes=0-
Chrome starts a range request (requesting everything from the first byte), so if your Go application does not support this, you have problems. See Answer # 2.
Answer # 2
HTTP/1.1 206 Partial Content Accept-Ranges: bytes Content-Length: 104715956 Content-Range: bytes 0-104715955/104715956 Content-Type: video/mp4
http.ServeFile() behaves well and correctly responds to a range request ( HTTP 206 Partial Content status code and Content-Range header) and sends the requested range (all in this case).
Your sample code does not respond with HTTP 206 Partial Content , but with plain HTTP 200 OK . When Chrome receives an unexpected HTTP 200 OK , the moment it refuses to play your video. If the video file is small, Chrome will not make anything out of it because it will simply accept an HTTP 200 OK response (and most likely will just save a small video in memory or in a cache file).