{"record":{"id":"88bc9f9a2a91c452","repo":"ZhuLinsen/daily_stock_analysis","slug":"source-name-is-required","errorCode":null,"errorMessage":"source name is required","messagePattern":"source name is required","errorType":"validation","errorClass":"IntelligenceServiceError","httpStatus":400,"severity":"error","filePath":"src/services/intelligence_service.py","lineNumber":370,"sourceCode":"        finally:\n            with cls._auto_fetch_condition:\n                cls._auto_fetch_last_run_at = datetime.now()\n                cls._auto_fetch_last_result = dict(result)\n                cls._auto_fetch_in_progress = False\n                cls._auto_fetch_condition.notify_all()\n        return result\n\n    def _normalize_source_fields(self, payload: Dict[str, Any]) -> Dict[str, Any]:\n        name = str(payload.get(\"name\") or \"\").strip()\n        url = str(payload.get(\"url\") or \"\").strip()\n        source_type = str(payload.get(\"source_type\") or \"rss\").strip().lower()\n        scope_type = str(payload.get(\"scope_type\") or \"market\").strip().lower()\n        scope_value = str(payload.get(\"scope_value\") or \"\").strip() or None\n        market = str(payload.get(\"market\") or \"cn\").strip().lower()\n        enabled = bool(payload.get(\"enabled\", True))\n        description = str(payload.get(\"description\") or \"\").strip() or None\n        if not name:\n            raise IntelligenceServiceError(\"source name is required\")\n        if not url:\n            raise IntelligenceServiceError(\"source url is required\")\n        if source_type not in _ALLOWED_SOURCE_TYPES:\n            raise IntelligenceServiceError(f\"unsupported source_type: {source_type}\")\n        if scope_type not in _ALLOWED_SCOPE_TYPES:\n            raise IntelligenceServiceError(f\"unsupported scope_type: {scope_type}\")\n        if scope_type in {\"symbol\", \"sector\"} and not scope_value:\n            raise IntelligenceServiceError(f\"scope_value is required when scope_type={scope_type}\")\n        if market not in _ALLOWED_MARKETS:\n            raise IntelligenceServiceError(f\"unsupported market: {market}\")\n        return {\n            \"name\": name[:100],\n            \"source_type\": source_type,\n            \"url\": url,\n            \"enabled\": enabled,\n            \"scope_type\": scope_type,\n            \"scope_value\": scope_value[:64] if scope_value else None,\n            \"market\": market,","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/intelligence_service.py#L352-L388","documentation":"Validation in _normalize_source_fields: the name field, after str()/strip(), is empty. Every source-creating/updating path (create_source, create_source_from_template, create_default_sources, test_source) funnels through this normalizer, so a blank name fails everywhere consistently.","triggerScenarios":"POSTing a source with name omitted, empty string, or whitespace-only; overrides payload passing name=None.","commonSituations":"Form submitted without the required field; API client sending {'name': ''}; template override accidentally blanking the name.","solutions":["Provide a non-empty name (max 100 chars after strip)","Add required-field validation in the client form before submit","If overriding from a template, don't include a name key to keep the template's name"],"exampleFix":"# before\nsvc.create_source({'name': '  ', 'url': 'https://...'})  # -> error\n# after\nsvc.create_source({'name': '财联社快讯', 'url': 'https://...'})","handlingStrategy":"validation","validationCode":"name = str(payload.get('name') or '').strip()\nif not name:\n    raise UserError('名称不能为空')","typeGuard":"def has_source_name(payload: dict) -> bool:\n    return bool(str(payload.get('name') or '').strip())","tryCatchPattern":"try:\n    svc.create_source(payload)\nexcept IntelligenceServiceError as e:\n    if 'name is required' in str(e):\n        focus_field('name')\n    else:\n        raise","preventionTips":["Mark name required in the create-source form","Strip whitespace client-side before submit","When overriding templates, omit the name key to inherit the template's name"],"tags":["validation","intelligence","required-field"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}