ZhuLinsen/daily_stock_analysis · error · IntelligenceServiceError

Intelligence source not found: {source_id}

Error message

Intelligence source not found: {source_id}

What it means

fetch_source raises IntelligenceServiceError when repo.get_source(source_id) returns None — the id does not exist in the intelligence_sources table (already deleted, or never created).

Source

Thrown at src/services/intelligence_service.py:255

            "total": total,
            "page": max(1, int(filters.get("page") or 1)),
            "page_size": max(1, min(int(filters.get("page_size") or 50), 100)),
        }

    def test_source(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        fields = self._normalize_source_fields(payload)
        entries = self._fetch_feed_entries(fields, limit=min(5, self.config.news_intel_max_items_per_source))
        return {
            "ok": True,
            "source": self._redact_source_fields(fields),
            "fetched_count": len(entries),
            "sample_items": [self._feed_entry_to_dict(entry) for entry in entries[:5]],
        }

    def fetch_source(self, source_id: int, *, dry_run: bool = False) -> Dict[str, Any]:
        source = self.repo.get_source(source_id)
        if source is None:
            raise IntelligenceServiceError(f"Intelligence source not found: {source_id}")
        if not source.enabled:
            raise IntelligenceServiceError(f"Intelligence source is disabled: {source_id}")
        now = datetime.now()
        try:
            entries = self._fetch_feed_entries(self._source_to_fields(source), limit=self.config.news_intel_max_items_per_source)
            item_fields = [self._entry_to_item_fields(entry, source, now) for entry in entries]
            saved = 0 if dry_run else self.repo.upsert_items(item_fields)
            deleted = 0 if dry_run else self.repo.apply_retention(self.config.news_intel_retention_days)
            if not dry_run:
                self.repo.update_source_status(source.id, status="success", error=None, fetched_at=now)
            return {
                "ok": True,
                "source_id": source.id,
                "fetched_count": len(entries),
                "saved_count": saved,
                "retention_deleted": deleted,
                "dry_run": dry_run,
                "sample_items": [self._feed_entry_to_dict(entry) for entry in entries[:5]],

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Refresh the source list before acting on it; remove deleted rows from UI state on delete confirmation
  2. Handle this error as 404-equivalent and stop retrying — retrying will not resurrect the row
  3. If id seems valid, verify against list_sources output

Example fix

# before
svc.fetch_source(deleted_id)  # -> not found
# after
src = next((s for s in svc.list_sources()['items'] if s['id']==sid), None)
if src is None:
    refresh_ui_list()
else:
    svc.fetch_source(sid)
Defensive patterns

Strategy: try-catch

Validate before calling

src = svc.repo.get_source(source_id)  # or via API GET detail
if src is None:
    remove_from_ui_list(source_id); refresh()

Try / catch

try:
    svc.fetch_source(sid)
except IntelligenceServiceError as e:
    if 'not found' in str(e):
        drop_stale_row(sid)  # 404-equivalent: stop retrying
    else:
        raise

Prevention

When it happens

Trigger: POST /fetch for a source id deleted in another tab/session; id from a stale list response; hand-crafted id.

Common situations: Two admins editing concurrently; frontend state holding a deleted row; re-running an old request after DB reset.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/80bf6798f41a32da. Report an issue: GitHub.