{"record":{"id":"167661425ce9553d","repo":"OpenBB-finance/OpenBB","slug":"prompt-name-v-should-be-a-valid-identifier","errorCode":null,"errorMessage":"Prompt name '{v}' should be a valid identifier","messagePattern":"Prompt name '(.+?)' should be a valid identifier","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openbb_platform/extensions/mcp_server/openbb_mcp_server/models/mcp_config.py","lineNumber":127,"sourceCode":"        open_braces = v.count(\"{\")\n        close_braces = v.count(\"}\")\n        if open_braces != close_braces:\n            raise ValueError(\n                f\"Unmatched braces in prompt content: {open_braces} opening, {close_braces} closing\"\n            )\n\n        return v\n\n    @field_validator(\"name\")\n    @classmethod\n    def validate_name(cls, v: str | None) -> str | None:\n        \"\"\"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.\"\"\"","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/extensions/mcp_server/openbb_mcp_server/models/mcp_config.py#L109-L145","documentation":"Pydantic validation error on PromptConfigModel.name: the provided name (after strip) does not match ^[a-zA-Z_][a-zA-Z0-9_]*$, i.e. it is not identifier-like. Prompt names become tool/resource identifiers on the MCP server, so dashes, spaces, dots, and leading digits are rejected.","triggerScenarios":"Naming a prompt 'my-prompt', '1_greet', 'greet.me', or 'daily report' in the config; deriving names from human titles or file names with hyphens; non-ASCII names.","commonSituations":"Slugs with hyphens copied from URLs; prompts generated from markdown headings; names mirroring filenames like 'my-prompt.md'.","solutions":["Use snake_case identifiers: 'my-prompt' → 'my_prompt'.","Start with a letter or underscore; strip file extensions and punctuation.","Leave name unset to let the server auto-generate a valid one."],"exampleFix":"# before\nprompts:\n  - name: daily-report\n    content: \"...\"\n\n# after\nprompts:\n  - name: daily_report\n    content: \"...\"","handlingStrategy":"validation","validationCode":"import re\n\ndef prompt_name_or_none(name: str | None) -> str | None:\n    if name is None:\n        return None\n    n = re.sub(r\"[^a-zA-Z0-9_]+\", \"_\", name.strip()).strip(\"_\")\n    n = f\"_{n}\" if n[:1].isdigit() else n\n    assert re.match(r\"^[a-zA-Z_][a-zA-Z0-9_]*$\", n), f\"unusable name {name!r}\"\n    return n","typeGuard":"def is_identifier_like(name: str | None) -> bool:\n    return name is None or (bool(name.strip()) and bool(re.match(r\"^[a-zA-Z_][a-zA-Z0-9_]*$\", name.strip())))","tryCatchPattern":null,"preventionTips":["Use snake_case prompt names; no hyphens, dots, spaces, or leading digits.","Leave name unset to get a server-generated valid identifier.","Sanitize names derived from titles or filenames at generation time."],"tags":["openbb","mcp","pydantic","prompts","naming"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}