ZhuLinsen/daily_stock_analysis · error · IntelligenceServiceError
intelligence source name already exists: {fields['name']}
Error message
intelligence source name already exists: {fields['name']} What it means
IntelligenceService.create_source maps a DB IntegrityError (unique constraint on source name) into an IntelligenceServiceError. _normalize_source_fields strips and truncates the name to 100 chars before insert, so the collision is on the normalized name.
Source
Thrown at src/services/intelligence_service.py:153
):
self.repo = repository or IntelligenceRepository()
self.config = config or get_config()
@classmethod
def reset_auto_fetch_state(cls) -> None:
with cls._auto_fetch_condition:
cls._auto_fetch_in_progress = False
cls._auto_fetch_last_run_at = None
cls._auto_fetch_last_result = None
cls._auto_fetch_condition.notify_all()
def create_source(self, payload: Dict[str, Any]) -> Dict[str, Any]:
fields = self._normalize_source_fields(payload)
self._validate_url(fields["url"])
try:
return self._source_to_dict(self.repo.create_source(fields))
except IntegrityError as exc:
raise IntelligenceServiceError(f"intelligence source name already exists: {fields['name']}") from exc
def list_sources(self, **filters: Any) -> Dict[str, Any]:
rows, total = self.repo.list_sources(**filters)
return {
"items": [self._source_to_dict(row) for row in rows],
"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 list_source_templates(self, **filters: Any) -> Dict[str, Any]:
market = str(filters.get("market") or "").strip().lower()
source_type = str(filters.get("source_type") or "").strip().lower()
templates = []
for template in self._builtin_source_templates():
if market and template["market"] != market:
continue
if source_type and template["source_type"] != source_type:View on GitHub (pinned to 5159bd72e8)
Solutions
- List existing sources first (list_sources) and reuse or pick a distinct name
- Make the create UI idempotent: disable submit while in flight and surface the duplicate error as a form-field message
- On collision, switch to update_source with the existing id instead
Example fix
# before
svc.create_source({'name': '财联社', 'url': '...'}) # duplicate -> error
# after
existing = next((s for s in svc.list_sources()['items'] if s['name']=='财联社'), None)
if existing:
svc.update_source(existing['id'], {'url': '...'})
else:
svc.create_source({'name': '财联社', 'url': '...'}) Defensive patterns
Strategy: try-catch
Validate before calling
existing = {s['name'] for s in svc.list_sources(page_size=100)['items']}
if payload['name'].strip() in existing:
raise UserError('同名数据源已存在,请换一个名称') Try / catch
try:
svc.create_source(payload)
except IntelligenceServiceError as e:
if 'already exists' in str(e):
show_field_error('name', '该名称已被占用')
else:
raise Prevention
- Disable the submit button while the request is in flight (prevents double-click duplicates)
- Check name uniqueness against a fresh list_sources before create
- Treat 'already exists' as a form validation error, not a 500
When it happens
Trigger: POSTing a source whose name (after strip) equals an existing row's name; concurrent double-submit of the same create form; create_default_sources run after sources were already created.
Common situations: User double-clicks 'Create'; template-based creation colliding with previously created defaults; whitespace-only differences mistaken for unique names.
Related errors
- internal_error
- internal_error
- history deletion made no progress
- portfolio_busy
- Intelligence source template not found: {template_id}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/0e964de0fcd836db.
Report an issue: GitHub.