OpenBB-finance/OpenBB · error · ValueError
Invalid format for URLs. Must be str, dict, or list.
Error message
Invalid format for URLs. Must be str, dict, or list.
What it means
Raised by the Pydantic field validator on the 'urls' field of the WeatherBulletinDownloadQueryParams model (weather_bulletin_download.py). The validator normalizes a str (comma-split), a dict containing an 'urls' key, or a list into a list of URLs; any other Python type (int, tuple, None, set) raises this ValueError and fails parameter validation.
Source
Thrown at openbb_platform/core/openbb_core/provider/standard_models/weather_bulletin_download.py:28
urls: str | dict | list = Field(
kw_only=True,
description="URLs for reports to download.",
)
@field_validator("urls", mode="before", check_fields=False)
@classmethod
def _validate_urls(cls, v):
"""Validate URLs input."""
if isinstance(v, str):
if "," in v:
return v.split(",")
return [v]
if isinstance(v, dict) and "urls" in v:
return v["urls"]
if isinstance(v, list):
return v
raise ValueError("Invalid format for URLs. Must be str, dict, or list.")
class WeatherBulletinDownloadData(Data):
"""Weather Bulletin Data."""
content: str = Field(
description="Base64 encoded content of the weather bulletin document.",
)
View on GitHub (pinned to 3e071fcc2c)
Solutions
- Pass urls as a list of strings: urls=['https://...pdf']
- Or a comma-separated string for multiple URLs: urls='https://a.pdf,https://b.pdf'
- Or a dict with the exact key 'urls': urls={'urls': [...]}; note the key must literally be 'urls'
- If the value comes from user input/JSON, coerce to list before the call: urls=list(value) when isinstance(value, (list, tuple, set))
Example fix
# before
res = await obb.economy.weather.bulletin.download(urls=("https://example.com/bulletin.pdf",)) # tuple -> ValueError
# after
res = await obb.economy.weather.bulletin.download(urls=["https://example.com/bulletin.pdf"]) # list Defensive patterns
Strategy: validation
Validate before calling
def normalize_weather_urls(v) -> list[str]:
if isinstance(v, str):
return v.split(",")
if isinstance(v, dict) and "urls" in v:
return list(v["urls"])
if isinstance(v, (list, tuple)):
return [str(u) for u in v]
raise TypeError(f"urls must be str/dict/list, got {type(v).__name__}")
urls = normalize_weather_urls(raw_urls) Type guard
from typing import Any
def is_valid_urls_input(v: Any) -> bool:
return (
isinstance(v, str)
or (isinstance(v, dict) and "urls" in v)
or (isinstance(v, list) and all(isinstance(u, str) for u in v))
) Try / catch
from pydantic import ValidationError
try:
res = await obb.economy.weather.bulletin.download(urls=urls)
except ValidationError as e:
bad = [err for err in e.errors() if err["loc"] == ("urls",)]
if bad:
urls = [str(urls)] # last-resort coercion
res = await obb.economy.weather.bulletin.download(urls=urls) Prevention
- Always pass urls as a list of strings; treat str/dict as convenience forms only
- When receiving JSON from users, validate urls with a small schema (must be array of URL strings) before forwarding
- Watch out for JSON that decodes tuples as lists elsewhere but tuples in Python when calling the SDK directly
When it happens
Trigger: Calling obb.economy.weather.bulletin.download (or a provider fetcher reusing this QueryParams) with urls passed as a tuple, a dict without an 'urls' key, a plain number, or None. Also passing a nested dict like {'urls': 123} passes the dict branch but then fails downstream Pydantic list validation.
Common situations: Building the urls argument dynamically from another API that returns tuples/sets; sending JSON where urls is null; copy-pasting a single URL wrapped in parentheses (tuple) instead of brackets (list).
Related errors
- Required field missing -> symbol
- At least one extension type must be selected.
- Incorrect email or password
- Charting is not installed. Please install `openbb-charting`.
- Invalid command : route={route}
AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14).
Data as JSON: /api/errors/871e019e5f149b4a.
Report an issue: GitHub.