{"record":{"id":"25dfe9f7ff43ac54","repo":"mvanhorn/last30days-skill","slug":"error-resp-error","errorCode":null,"errorMessage":"error: {resp['error']}","messagePattern":"error: (.+?)","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"warning","filePath":"skills/last30days/scripts/lib/stocktwits.py","lineNumber":366,"sourceCode":"        \"url\": item.url,\n        \"timestamp\": newest or None,\n    }\n\n\n# --------------------------------------------------------------------------- #\n# Standalone CLI (ad-hoc use today, before any engine wiring)                  #\n#   python3 stocktwits.py \"ServiceNow stock\"                                   #\n# --------------------------------------------------------------------------- #\nif __name__ == \"__main__\":\n    topic = \" \".join(sys.argv[1:]) or \"$NOW\"\n    if not is_financial_topic(topic) and not detect_symbols(topic, resolve=False):\n        print(f\"Not a ticker/crypto topic — skipping StockTwits: {topic!r}\")\n        raise SystemExit(0)\n    today = datetime.date.today()\n    since = (today - datetime.timedelta(days=30)).isoformat()\n    resp = search_stocktwits(topic, from_date=since, depth=\"default\")\n    if resp.get(\"error\") and not resp.get(\"messages\"):\n        print(\"error:\", resp[\"error\"]); raise SystemExit(1)\n    items = parse_stocktwits_response(resp, query=topic)\n    agg = aggregate_sentiment(resp[\"messages\"])\n    print(f\"symbol(s): {resp.get('symbols')} | watchlist {resp.get('watchlist')}\")\n    print(f\"sentiment: {agg['bullish']} bull / {agg['bearish']} bear \"\n          f\"({agg['pct_bullish']}% bullish of tagged) over {agg['sample']} msgs\")\n    for it in sorted(items, key=lambda x: x[\"engagement\"][\"likes\"], reverse=True)[:8]:\n        s = it[\"metadata\"][\"sentiment\"] or \"-\"\n        print(f\"  [{it['engagement']['likes']}♥ {s}] @{it['author']}: {it['snippet'][:120]}\")\n","sourceCodeStart":348,"sourceCodeEnd":375,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/stocktwits.py#L348-L375","documentation":"Not a Python exception - the standalone CLI branch of stocktwits.py prints 'error: <message>' and exits with SystemExit(1) when search_stocktwits returned an 'error' key and zero messages. The error string comes from the dict envelope: either 'no symbol resolved' (no ticker detected) or the stringified exception from a failed stream fetch.","triggerScenarios":"python3 stocktwits.py 'ServiceNow stock' where the topic resolves no symbol, or where the stream fetch raises (network failure, StockTwits block) so the except branch returns messages=[] plus an error string; the CLI then prints the error and exits nonzero.","commonSituations":"Passing a non-financial phrase that dodges detect_symbols; running the CLI behind a firewall or from a blocked datacenter IP; StockTwits API downtime; empty argv defaulting to $NOW during an outage.","solutions":["Check the exit code ($?) when scripting around this CLI and read the printed error to classify: symbol resolution vs fetch failure","Pass an explicit cashtag ('$NOW') to bypass symbol-detection failures","For fetch failures, retry after a pause or from a different network; for resolution failures, change the topic wording","Prefer importing search_stocktwits and inspecting the returned dict instead of parsing CLI stdout"],"exampleFix":"# before\npython3 stocktwits.py \"how about that stock\"  # error: no symbol resolved; exit 1\n\n# after\npython3 stocktwits.py \"$NOW\"  # explicit cashtag, detection bypassed","handlingStrategy":"validation","validationCode":"from lib.stocktwits import detect_symbols, _CASHTAG\n\ntopic = \" \".join(sys.argv[1:]) or \"$NOW\"\nif not _CASHTAG.fullmatch(\"$\" + topic.lstrip(\"$\")) and not detect_symbols(topic):\n    print(\"Not a ticker topic; skipping\")\n    raise SystemExit(0)","typeGuard":"def is_cashtag(topic: str) -> bool:\n    import re\n    return bool(re.fullmatch(r\"\\$[A-Z]{1,8}\", topic.strip().upper()))","tryCatchPattern":"resp = search_stocktwits(topic, from_date=since)\nif resp.get(\"error\") and not resp.get(\"messages\"):\n    # programmatic path: inspect the envelope instead of parsing CLI stdout\n    handle_error(resp[\"error\"])","preventionTips":["Check the exit code when wrapping this CLI in scripts","Pass explicit cashtags ($TICKER) to bypass symbol-detection misses","Prefer importing search_stocktwits over shelling out - the dict envelope is richer than stdout"],"tags":["stocktwits","cli","exit-code","symbol-resolution"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}