NousResearch/hermes-agent · warning · ValueError
Video at {url} was empty (0 bytes).
Error message
Video at {url} was empty (0 bytes). What it means
ValueError from agent/video_gen_provider.py:320: the streamed download of the generated video completed but wrote zero bytes, so the (empty) partial file is unlinked and the error raised. It distinguishes 'server returned nothing at this URL' from other failures.
Source
Thrown at agent/video_gen_provider.py:320
continue
bytes_written += len(chunk)
if bytes_written > max_bytes:
fh.close()
try:
path.unlink()
except OSError:
pass
raise ValueError(
f"Video at {url} exceeds {max_bytes // (1024 * 1024)}MB cap; refusing to cache."
)
fh.write(chunk)
if bytes_written == 0:
try:
path.unlink()
except OSError:
pass
raise ValueError(f"Video at {url} was empty (0 bytes).")
return path
def success_response(
*,
video: str,
model: str,
prompt: str,
modality: str = "text",
aspect_ratio: str = "",
duration: int = 0,
provider: str,
extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""Build a uniform success response dict.
``video`` may be an HTTP URL or an absolute filesystem path.View on GitHub (pinned to c896c09c42)
Solutions
- Verify the URL outside the app: curl -sL <url> -o /tmp/v && ls -l /tmp/v — 0 bytes confirms the provider side.
- Retry the download after a short delay (asset propagation lag right after job completion is the most common cause).
- Regenerate or re-request the asset URL if the signed link expired.
- If persistent, check the provider's status page / job logs for a partial-failure state.
Example fix
# before (single attempt, empty body aborts the whole generation)
path = _cache_video(url, max_bytes)
# after (one bounded retry for propagation lag)
for attempt in range(2):
try:
path = _cache_video(url, max_bytes)
break
except ValueError as exc:
if "was empty" not in str(exc) or attempt == 1:
raise
time.sleep(5) Defensive patterns
Strategy: retry
Validate before calling
import urllib.request
def url_has_body(url: str) -> bool:
req = urllib.request.Request(url, method="HEAD")
with urllib.request.urlopen(req, timeout=10) as r:
length = r.headers.get("Content-Length")
return length is None or int(length) > 0 Try / catch
for attempt in range(2):
try:
path = cache_video(url, max_bytes)
return path
except ValueError as exc:
if "was empty" not in str(exc) or attempt == 1:
raise
time.sleep(5) # asset propagation lag; retry once Prevention
- Expect empty bodies right after job completion; download after a short delay or with one retry.
- Use freshly issued asset URLs — expired signed URLs often return empty 200s.
- Verify suspicious URLs with curl -sL <url> -o test.bin && ls -l test.bin.
When it happens
Trigger: The video URL responds with an empty body — provider marked the job complete but the asset URL is not yet populated, a signed URL expired returning an empty 200, or a proxy/CDN hiccup delivered an empty stream.
Common situations: Racing a provider whose status turns 'completed' before the file is actually served; expired pre-signed S3/R2 URLs on retry; provider-side incident serving empty responses.
Related errors
- Video at {url} exceeds {max_bytes // (1024 * 1024)}MB cap; r
- video job {getattr(video, 'id', '?')} did not reach a termin
- Could not fetch image: ${response.status}
- Provider '{_explicit}' is set in config.yaml but no API key
- No LLM provider configured. Run `hermes model` to select a p
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/5d4ee0ce135ac15e.
Report an issue: GitHub.