{"record":{"id":"c23f49e6683f7be4","repo":"apache/superset","slug":"extension-name-must-start-with-a-letter-and-contai","errorCode":null,"errorMessage":"Extension name must start with a letter and contain only lowercase letters, numbers, and hyphens (e.g., 'dashboard-widgets')","messagePattern":"Extension name must start with a letter and contain only lowercase letters, numbers, and hyphens \\(e\\.g\\., 'dashboard-widgets'\\)","errorType":"exception","errorClass":"ExtensionNameError","httpStatus":null,"severity":"error","filePath":"superset-extensions-cli/src/superset_extensions_cli/utils.py","lineNumber":252,"sourceCode":"            \"Publisher must start with a letter and contain only lowercase letters, numbers, and hyphens (e.g., 'my-org')\"\n        )\n\n\ndef validate_technical_name(name: str) -> None:\n    \"\"\"\n    Validate technical extension name format.\n\n    Args:\n        name: Technical extension name (e.g., 'dashboard-widgets')\n\n    Raises:\n        ExtensionNameError: If name is invalid\n    \"\"\"\n    if not name:\n        raise ExtensionNameError(\"Extension name cannot be empty\")\n\n    if not TECHNICAL_NAME_REGEX.match(name):\n        raise ExtensionNameError(\n            \"Extension name must start with a letter and contain only lowercase letters, numbers, and hyphens (e.g., 'dashboard-widgets')\"\n        )\n\n\ndef validate_display_name(display_name: str) -> str:\n    \"\"\"\n    Validate and normalize display name format.\n\n    Args:\n        display_name: Human-readable extension name\n\n    Returns:\n        Cleaned display name\n\n    Raises:\n        ExtensionNameError: If display name is invalid\n    \"\"\"\n    if not display_name or not display_name.strip():","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset-extensions-cli/src/superset_extensions_cli/utils.py#L234-L270","documentation":"Thrown by validate_technical_name() when the name is non-empty but fails TECHNICAL_NAME_REGEX: it must start with a letter and contain only lowercase letters, numbers, and hyphens. The technical name becomes part of file paths and the module federation remote name, so the slug format is mandatory. Uppercase letters, underscores, dots, and leading digits or hyphens are all rejected.","triggerScenarios":"Calling `superset-extensions create my-org <name>` with names like 'DashboardWidgets' (camelCase), 'dashboard_widgets' (underscores), '1dashboard' (leading digit), '-widgets' (leading hyphen), or 'dashboard widgets' (space). Also direct calls to validate_technical_name() with such values.","commonSituations":"Deriving the technical name from a display name without kebab-casing; pasting npm package names that contain dots or scopes; camelCase muscle memory from JS identifiers.","solutions":["Convert the name to kebab-case: lowercase everything, replace spaces/underscores/dots with hyphens, strip leading/trailing hyphens (e.g. 'Dashboard Widgets' -> 'dashboard-widgets').","The CLI ships suggest_technical_name(display_name) — use it to generate a valid slug from a human name.","Ensure the first character is a lowercase letter, not a digit or hyphen."],"exampleFix":"# before\nsuperset-extensions create my-org DashboardWidgets\n# ExtensionNameError: Extension name must start with a letter ...\n\n# after\nsuperset-extensions create my-org dashboard-widgets","handlingStrategy":"validation","validationCode":"import re\nTECH_NAME_RE = re.compile(r\"^[a-z][a-z0-9-]*$\")\n\ndef technical_name_is_valid(name: str) -> bool:\n    return bool(name) and bool(TECH_NAME_RE.match(name))\n\ndef to_slug(name: str) -> str:\n    return re.sub(r\"^-+|-+$\", \"\", re.sub(r\"[^a-z0-9]+\", \"-\", name.lower()))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always derive technical names with a kebab-case slugify helper rather than hand-typing them.","Prefer the CLI's own suggest_technical_name(display_name) so the same rules validate and generate."],"tags":["cli","validation","naming","extensions","kebab-case"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}