xtekky/gpt4free · error · ValueError
Response must be a dict or have headers
Error message
Response must be a dict or have headers
What it means
Thrown by g4f.image.copy_media() (copy_images.py) when the response argument is neither a dict (with 'data'/'mimeType' keys) nor an object with .headers (e.g. an aiohttp/requests response), and no explicit content_type was passed. The function must know the media's MIME type to pick an extension and filename; with none of the three sources available it aborts.
Source
Thrown at g4f/image/copy_images.py:83
return str(int(timestamp)) + "_" + filename.split("_", maxsplit=1)[-1]
async def save_response_media(
response,
prompt: str,
tags: list[str] = None,
transcript: str = None,
content_type: str = None,
) -> AsyncIterator:
"""Save media from response to local file and return a response object."""
if isinstance(response, dict):
content_type = response.get("mimeType", content_type or "audio/mpeg")
transcript = response.get("transcript")
response = response.get("data")
elif hasattr(response, "headers"):
content_type = response.headers.get("content-type", content_type)
elif not content_type:
raise ValueError("Response must be a dict or have headers")
if isinstance(response, str):
response = base64.b64decode(response)
extension = MEDIA_TYPE_MAP.get(content_type)
if extension is None:
raise ValueError(f"Unsupported media type: {content_type}")
filename = get_filename(tags, prompt, f".{extension}", prompt)
if hasattr(response, "headers"):
filename = update_filename(response, filename)
target_path = os.path.join(get_media_dir(), filename)
ensure_media_dir()
with open(target_path, "wb") as f:
if isinstance(response, bytes):
f.write(response)
else:View on GitHub (pinned to 973504e177)
Solutions
- Pass the MIME type explicitly: copy_media(data, content_type='audio/mpeg', ...).
- Or pass the original response dict {'data': ..., 'mimeType': ...} if the provider returned one.
- Or pass the response object itself (with .headers) instead of pre-extracted bytes.
Example fix
// before return_media = await copy_media(audio_bytes, prompt=prompt, tags=tags) // after return_media = await copy_media(audio_bytes, prompt=prompt, tags=tags, content_type="audio/mpeg")
Defensive patterns
Strategy: validation
Validate before calling
def copy_media_ready(response, content_type) -> bool:
return (
isinstance(response, dict)
or hasattr(response, "headers")
or content_type is not None
) Prevention
- Always pass content_type when forwarding raw bytes or base64 strings.
- Prefer forwarding the provider's original response object (with .headers) instead of pre-extracted payloads.
When it happens
Trigger: copy_media(b'...mp3 bytes...') with content_type=None; copy_media('base64str') without content_type (str responses are decoded but still need a type); passing a custom response wrapper that exposes .content but not .headers.
Common situations: Adapters that already extracted bytes/str from a provider response and forward only the payload; newer provider return types (raw bytes) passed to a helper written around dict/curl_cffi responses.
Related errors
- Unsupported media type: {content_type}
- Unsupported media type: {media_type}
- Failed to upload file: {res_json}
- Upload failed: {result}
- {data['code']}:{data['details']}
AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14).
Data as JSON: /api/errors/70e10ef2bced8fba.
Report an issue: GitHub.