A successful HTTP request does not by itself prove that you downloaded a video. Before handing a response to a media processor, check the response status, its declared content type and a small prefix of the decoded body. If those signals look like HTML, JSON or an XML error document, stop the media handoff and investigate the delivery response.
This guide implements a conservative Python screening step for a worker expecting a complete binary audio or video file. It is not a media detector, an HTML parser or a replacement for validating the downloaded container.
Keep the API response separate from the media response
A job-status request and a file download have different purposes. Tornado's job-status reference describes a structured response containing the job ID, status and delivery fields. Save the identity and inspect the status before fetching the appropriate delivered artifact. The status JSON itself is not the video.
A common integration mistake is to save whichever response arrived to a filename ending in .mp4. Renaming an error document does not turn it into playable media. Another possible failure is a redirect that ends at an HTML login or access page. Diagnose the final response your downloader received, while keeping credentials and signed URLs out of logs.
Use three checks with different jobs
The HTTP status tells you how the request was handled. The Content-Type header declares the representation's media type, as defined in RFC 9110 section 8.3. A prefix check can flag some obvious contradictions between that declaration and the bytes.
None of these checks proves that the complete artifact is decodable. A server can label an error page incorrectly, and a damaged file can start like a normal binary file. Treat these signals as reasons to stop or continue validation, never as a certificate that the file is ready.
| Response observed | Next step |
|---|---|
| An error status | Classify the delivery error before retrying |
| HTML or JSON content type when expecting a video | Stop and inspect the request/response boundary |
| Binary content type but a prefix resembling HTML | Hold the artifact for diagnosis |
| Generic or missing content type and an inconclusive prefix | Continue to a format-aware validator |
| Recognizable container but missing required stream | Reject for the consumer even if the transfer succeeded |
Screen a bounded prefix in Python
This example deliberately handles only a full-file GET workflow expecting status 200. It rejects 206, because ranged downloads need a separate resume and range validation flow. It also rejects 204: no content is not a delivered audio or video artifact.
Call it with the final response's status and content type, and up to 512 bytes from the beginning of the decoded response body. Assemble that prefix across small stream chunks if necessary. Do not assume the first network chunk contains a complete HTML tag.
PREFIX_LIMIT = 512
def screen_binary_download(status, content_type, prefix):
if not isinstance(prefix, bytes):
raise TypeError("prefix must be bytes")
if len(prefix) > PREFIX_LIMIT:
raise ValueError("read at most 512 prefix bytes")
if status != 200:
return "stop_http_status"
media_type = (content_type or "").split(";", 1)[0].strip().lower()
if (media_type in {"text/html", "application/xhtml+xml",
"application/json", "application/xml", "text/xml"}
or media_type.endswith(("+json", "+xml"))):
return "stop_document_type"
head = prefix
if head.startswith(b"\xef\xbb\xbf"):
head = head[3:]
head = head.lstrip(b" \t\r\n").lower()
if not head:
return "hold_empty_or_whitespace_prefix"
if head.startswith((b"<!doctype html", b"<html", b"<?xml", b"{", b"[")):
return "hold_document_like_prefix"
return "needs_media_validation"
The helper uses Python's documented byte-string operations. It handles a UTF-8 byte-order mark at the beginning and ignores a small set of leading whitespace characters for its prefix heuristic. It does not parse JSON, XML or HTML. An opening brace is a reason to hold the response, not proof that its contents are a JSON error.
Keep this policy specific to binary audio/video. JSON metadata, XML manifests and text subtitles are legitimate artifacts in other workflows and need their own rules. Do not apply this function to every output from an API.
Preserve the prefix and validate the whole artifact
Reading bytes for inspection consumes them from a stream. If screening allows further work, write those same bytes to the temporary file before continuing with the remaining stream. Otherwise the downloaded file loses its beginning.
The helper does not make a network request or impose network timeouts. Your downloader still needs redirect policy, timeouts, transfer-size limits and bounded handling of content decoding. If the HTTP client has not decoded a content encoding, the sample may see compressed bytes instead of an HTML page. An inconclusive result must still go through validation.
Keep the artifact temporary until the transfer and required checks finish. Use the atomic download handoff guide to prevent a downstream worker from opening an incomplete destination. Then inspect the container and codecs against the consumer's requirements.
The prefix heuristic intentionally misses many documents: comments before an HTML tag, alternative encodings, long leading whitespace and text that starts with other tags. It can also hold a non-document whose initial bytes happen to match a pattern. Never use it as a security boundary, malware scanner or allowlist of safe media.
Diagnose without creating a retry loop
Record the local artifact ID, remote job ID, HTTP status, a bounded content-type value and the screening result. Avoid logging the response body by default: an error document can contain private details. Follow the signed URL logging guide for safe diagnostics.
A document-shaped response does not tell you whether the source job failed, access expired or the request targeted the wrong endpoint. Compare the job's recorded delivery information with the request you intended to make. Use the expired URL versus missing file guide before recreating a job or repeatedly requesting the same failing URL.
The published helper is tested locally against synthetic status, header and prefix fixtures, including its deliberate blind spots. Those checks do not exercise a live job, CDN, redirect chain, decompressor or media decoder. Add integration fixtures for your own HTTP client before relying on its stream behavior.
Build your first Tornado media workflow, then give the file-download boundary its own validation step. Keep job status, transfer success and consumer readiness as separate facts.
Pair response screening with explicit download timeouts so a stalled or endlessly slow transfer cannot keep waiting without an application policy.