{"record":{"id":"e7a4f1b4035d074f","repo":"OpenBB-finance/OpenBB","slug":"tag-cannot-be-empty-string","errorCode":null,"errorMessage":"Tag cannot be empty string","messagePattern":"Tag cannot be empty string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openbb_platform/extensions/mcp_server/openbb_mcp_server/models/mcp_config.py","lineNumber":139,"sourceCode":"        \"\"\"Validate prompt name if provided.\"\"\"\n        if v is not None:\n            if not v.strip():\n                raise ValueError(\"Prompt name cannot be empty string\")\n            # Check for valid identifier-like name\n            if not re.match(r\"^[a-zA-Z_][a-zA-Z0-9_]*$\", v.strip()):\n                raise ValueError(f\"Prompt name '{v}' should be a valid identifier\")\n        return v\n\n    @field_validator(\"tags\")\n    @classmethod\n    def validate_tags(cls, v: list[str]) -> list[str]:\n        \"\"\"Validate tags are non-empty strings.\"\"\"\n        validated_tags = []\n        for tag in v:\n            if not isinstance(tag, str):\n                raise ValueError(f\"Tag must be a string, got {type(tag)}\")\n            if not tag.strip():\n                raise ValueError(\"Tag cannot be empty string\")\n            validated_tags.append(tag.strip())\n        return validated_tags\n\n\nclass MCPConfigModel(BaseModel):\n    \"\"\"Model for validating the main MCP configuration structure.\"\"\"\n\n    expose: bool | None = Field(\n        default=None, description=\"Whether to expose this route (False = exclude).\"\n    )\n    mcp_type: MCPType | None = Field(\n        default=None, description=\"MCP type classification for the route.\"\n    )\n    methods: list[HTTPMethod] | None = Field(\n        default=None, description=\"HTTP methods to include for this route.\"\n    )\n    prompts: list[PromptConfigModel] = Field(\n        default_factory=list, description=\"Prompt configurations for this route.\"","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/extensions/mcp_server/openbb_mcp_server/models/mcp_config.py#L121-L157","documentation":"Raised by the 'tags' field validator on an MCP prompt/route config model. Every entry in the 'tags' list must be a non-blank string; a tag that is empty or contains only whitespace is rejected so that tag-based filtering of MCP routes stays reliable. It surfaces as a pydantic ValidationError when the openapi_extra 'mcp_config' (or 'x-mcp') block is parsed.","triggerScenarios":"Setting openapi_extra={\"mcp_config\": {\"tags\": [\"\"]}} or {\"tags\": [\"news\", \"   \"]]} on a FastAPI route, or embedding an empty tag in the MCP config dict passed to validate_mcp_config. Strict mode (default) raises; non-strict mode logs a warning and falls back to an empty config.","commonSituations":"YAML/JSON config files with trailing commas producing empty strings, template-generated tag lists that emit blank entries, copy-paste configs where an optional tag was deleted but its quotes left behind.","solutions":["Remove or fill in the empty/whitespace-only tag in the route's openapi_extra mcp_config.tags list","Strip/filter blank strings before passing tags: [t for t in tags if t and t.strip()]","If the config comes from user input, validate it with validate_mcp_config(config, strict=False) first to get a warning instead of a hard failure"],"exampleFix":"# before\nopenapi_extra={\"mcp_config\": {\"tags\": [\"equities\", \"\"]}}\n\n# after\nopenapi_extra={\"mcp_config\": {\"tags\": [\"equities\"]}}","handlingStrategy":"validation","validationCode":"tags = cfg.get(\"tags\", [])\nif any(not isinstance(t, str) or not t.strip() for t in tags):\n    raise ValueError(\"mcp_config.tags contains a blank or non-string entry\")\ncfg[\"tags\"] = [t.strip() for t in tags]","typeGuard":"def has_valid_tags(cfg: dict) -> bool:\n    tags = cfg.get(\"tags\", [])\n    return (\n        isinstance(tags, list)\n        and all(isinstance(t, str) and t.strip() for t in tags)\n    )","tryCatchPattern":"try:\n    model = validate_mcp_config(cfg)\nexcept ValidationError as e:\n    if \"Tag cannot be empty\" in str(e):\n        cfg[\"tags\"] = [t.strip() for t in cfg.get(\"tags\", []) if t.strip()]\n        model = validate_mcp_config(cfg)\n    else:\n        raise","preventionTips":["Strip and filter tag lists at the edge before they reach pydantic","Add a lint rule or unit test asserting all configured tags are non-blank strings","Use strict=False during config import to downgrade to warnings while authoring"],"tags":["pydantic","validation","mcp","config"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}