{"record":{"id":"96c64b3410d10a51","repo":"apache/superset","slug":"package-name-name-cannot-start-with-a-number","errorCode":null,"errorMessage":"Package name '{name}' cannot start with a number","messagePattern":"Package name '(.+?)' cannot start with a number","errorType":"exception","errorClass":"ExtensionNameError","httpStatus":null,"severity":"error","filePath":"superset-extensions-cli/src/superset_extensions_cli/utils.py","lineNumber":195,"sourceCode":"    return kebab_name.replace(\"-\", \"_\")\n\n\ndef name_to_kebab_case(name: str) -> str:\n    \"\"\"Convert display name directly to kebab-case (e.g., 'Hello World' -> 'hello-world').\"\"\"\n    normalized = _normalize_for_identifiers(name)\n    return _normalized_to_kebab(normalized)\n\n\ndef validate_python_package_name(name: str) -> None:\n    \"\"\"\n    Validate Python package name (snake_case format).\n\n    Raises:\n        ExtensionNameError: If name is invalid\n    \"\"\"\n    # Check if it starts with a number (invalid for Python identifiers)\n    if name[0].isdigit():\n        raise ExtensionNameError(f\"Package name '{name}' cannot start with a number\")\n\n    # Check if the first part (before any underscore) is a Python keyword\n    if (first_part := name.split(\"_\")[0]) in PYTHON_KEYWORDS:\n        raise ExtensionNameError(\n            f\"Package name cannot start with Python keyword '{first_part}'\"\n        )\n\n    # Check if it's a valid Python identifier\n    if not name.replace(\"_\", \"a\").isalnum():\n        raise ExtensionNameError(f\"'{name}' is not a valid Python package name\")\n\n\ndef validate_npm_package_name(name: str) -> None:\n    \"\"\"\n    Validate npm package name (kebab-case format).\n\n    Raises:\n        ExtensionNameError: If name is invalid","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset-extensions-cli/src/superset_extensions_cli/utils.py#L177-L213","documentation":"Part of the Superset extensions CLI scaffolder validation. validate_python_package_name rejects names whose first character is a digit, because Python identifiers (and thus the generated package/module names) cannot start with a number. The rejected name is included in the ExtensionNameError message.","triggerScenarios":"Running the extensions CLI new/create command with an extension name like '2fa-auth' or '4xx' whose normalized snake_case package name starts with a digit.","commonSituations":"Product names that begin with a number ('3d-viewer'); names normalized from camelCase where the leading token is numeric; scripted scaffolding feeding arbitrary strings.","solutions":["Choose a name starting with a letter, e.g. 'view3d' instead of '3dview'.","Prefix numeric-leading names with a letter word: 'auth-2fa'.","Pre-validate names in any automation that calls the CLI."],"exampleFix":"# before\n$ superset-extension new 2fa-auth\n# after\n$ superset-extension new auth-2fa","handlingStrategy":"validation","validationCode":"def valid_python_package_prefix(name: str) -> bool:\n    return bool(name) and not name[0].isdigit()","typeGuard":null,"tryCatchPattern":"from superset_extensions_cli.utils import ExtensionNameError\n\ntry:\n    validate_python_package_name(name)\nexcept ExtensionNameError as e:\n    print(f'Pick a different extension name: {e}')\n    sys.exit(2)","preventionTips":["Start extension names with a letter; lead with a word when the brand begins with a digit (auth-2fa, view3d).","Pre-validate names in scripts before invoking the CLI."],"tags":["cli","validation","scaffolding","python"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}