mvanhorn/last30days-skill · error · ValueError
StockTwits item has no symbol
Error message
StockTwits item has no symbol
What it means
ValueError raised in StockTwits refetch_datum when the symbol needed to rebuild the stream URL cannot be found - both item.metadata['symbol'] and item.container are empty after strip/upper. Without a symbol there is no /streams/symbol/<S>.json endpoint to query, so re-fetch is impossible.
Source
Thrown at skills/last30days/scripts/lib/stocktwits.py:310
tagged = bull + bear
return {
"bullish": bull,
"bearish": bear,
"untagged": len(messages) - tagged,
"pct_bullish": round(100 * bull / tagged) if tagged else None,
"sample": len(messages),
}
def refetch_datum(item: Any, datum_key: str) -> dict[str, Any]:
"""Re-fetch the same paginated, date-filtered symbol-stream population."""
from . import http
if datum_key != "pct_bullish":
raise KeyError(f"Unsupported StockTwits datum: {datum_key}")
symbol = str(item.metadata.get("symbol") or item.container or "").strip().upper()
if not symbol:
raise ValueError("StockTwits item has no symbol")
url = _STREAM_URL.format(symbol=urllib.parse.quote(symbol))
window = item.metadata.get("freshness_window") or {}
depth = str(window.get("depth") or "default")
target = _DEPTH.get(depth, _DEPTH["default"])
messages: list[dict[str, Any]] = []
cursor_max = None
while len(messages) < target:
request_kwargs: dict[str, Any] = {"timeout": 10, "retries": 2}
if cursor_max:
request_kwargs["params"] = {"max": cursor_max}
data = http.request("GET", url, **request_kwargs)
if not isinstance(data, dict) or not isinstance(data.get("messages"), list):
raise KeyError("StockTwits symbol stream was not returned")
batch = data["messages"]
if not batch:
break
messages.extend(batch)
cursor = data.get("cursor") or {}View on GitHub (pinned to c7460f6114)
Solutions
- Ensure ingest stores the resolved symbol in item.metadata['symbol']
- Guard before calling: skip refetch when neither metadata symbol nor container is non-empty
- Re-run search_stocktwits for the topic to rebuild a fully-populated item
Example fix
# before
datum = refetch_datum(item, "pct_bullish") # no symbol anywhere
# after
symbol = (item.metadata.get("symbol") or item.container or "").strip().upper()
if not symbol:
skip(item)
else:
datum = refetch_datum(item, "pct_bullish") Defensive patterns
Strategy: validation
Validate before calling
symbol = str(item.metadata.get("symbol") or getattr(item, "container", "") or "").strip().upper()
if not symbol:
skip_refetch(item) # cannot rebuild the stream URL without a symbol Type guard
def item_has_stocktwits_symbol(item) -> bool:
return bool(
str(item.metadata.get("symbol") or getattr(item, "container", "") or "").strip()
) Try / catch
try:
datum = refetch_datum(item, "pct_bullish")
except ValueError as e:
if "no symbol" in str(e):
skip_refetch(item) # data-quality gap; re-ingest, don't retry Prevention
- Write the resolved symbol into item.metadata['symbol'] at ingest
- Guard refetch scheduling on symbol presence
- Rebuild items via search_stocktwits rather than manual construction
When it happens
Trigger: refetch_datum(item, 'pct_bullish') on an item whose metadata dict lacks 'symbol' and whose container attribute is empty/None - typically items constructed manually or deserialized from a schema that dropped metadata.
Common situations: Persisted items losing metadata across schema migrations; test fixtures built without metadata; items created via parse paths that only set container sometimes; refetch attempted on non-symbol (watchlist) items.
Related errors
- Polymarket item has no event id or slug
- Polymarket item carries no event id; slug equality alone can
- Expected JSON response, got empty text
- unknown audience register {name!r}; choose one of: {choices}
- StockTwits symbol stream was not returned
AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15).
Data as JSON: /api/errors/9963f468a1420d08.
Report an issue: GitHub.