{"record":{"id":"7da4c367b1c6d040","repo":"apache/superset","slug":"database-not-found-7da4c3","errorCode":null,"errorMessage":"Database not found","messagePattern":"Database not found","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"superset/daos/database.py","lineNumber":275,"sourceCode":"                SqlaTable.database_id == database_id,\n                SqlaTable.catalog == catalog,\n                SqlaTable.schema == schema,\n            )\n            .all()\n        )\n\n    @classmethod\n    def is_odps_partitioned_table(\n        cls, database: Database, table_name: str\n    ) -> tuple[bool, list[str]]:\n        \"\"\"\n        This function is used to determine and retrieve\n        partition information of the ODPS table.\n        The return values are whether the partition\n        table is partitioned and the names of all partition fields.\n        \"\"\"\n        if not database:\n            raise ValueError(\"Database not found\")\n        if database.backend != \"odps\":\n            return False, []\n        if ODPS is None:\n            logger.warning(\"pyodps is not installed, cannot check ODPS partition info\")\n            return False, []\n        uri = database.sqlalchemy_uri\n        access_key = database.password\n        pattern = re.compile(\n            r\"odps://(?P<username>[^:]+):(?P<password>[^@]+)@(?P<project>[^/]+)/(?:\\?\"\n            r\"endpoint=(?P<endpoint>[^&]+))\"\n        )\n        if not uri or not isinstance(uri, str):\n            logger.warning(\n                \"Invalid or missing sqlalchemy URI, please provide a correct URI\"\n            )\n            return False, []\n        if match := pattern.match(unquote(uri)):\n            access_id = match.group(\"username\")","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/daos/database.py#L257-L293","documentation":"Plain ValueError('Database not found') raised at the top of DatabaseDAO.is_odps_partitioned_table: the caller passed a falsy `database` (None or an unloaded/empty object). Everything after it (ODPS backend check, pyodps import guard, URI parsing) assumes a real Database instance.","triggerScenarios":"Calling DatabaseDAO.is_odps_partitioned_table(None, table_name), or passing a database variable that came back None from a prior lookup (e.g. find_by_id miss) without checking.","commonSituations":"Fork/plugin code doing `db = DatabaseDAO.find_by_id(i); DatabaseDAO.is_odps_partitioned_table(db, t)` where the id doesn't exist; dataset flows where dataset.database resolved to None.","solutions":["Resolve and verify the Database before calling: `db_obj = DatabaseDAO.find_by_id(id); if db_obj is None: raise/handle` then call with db_obj.","Guard at the call site with a truthiness check when the database is optional in your flow."],"exampleFix":"# before\ndatabase = DatabaseDAO.find_by_id(maybe_missing_id)\nparts = DatabaseDAO.is_odps_partitioned_table(database, \"my_table\")\n\n# after\ndatabase = DatabaseDAO.find_by_id(maybe_missing_id)\nif database is None:\n    raise DatabaseNotFoundError()  # or return early\nparts = DatabaseDAO.is_odps_partitioned_table(database, \"my_table\")","handlingStrategy":"type-guard","validationCode":"def has_database(database) -> bool:\n    return database is not None","typeGuard":"from superset.models.core import Database\n\ndef is_loaded_database(obj) -> bool:\n    return isinstance(obj, Database) and obj.id is not None","tryCatchPattern":"try:\n    DatabaseDAO.is_odps_partitioned_table(database, table)\nexcept ValueError as ex:\n    if ex.args[0] == \"Database not found\":\n        # upstream lookup missed: re-raise as a 404-style error\n        raise DatabaseNotFoundError() from ex\n    raise","preventionTips":["Never chain find_by_id() results into DAO calls without a None check.","Treat a None database from any lookup as an error at that site."],"tags":["dao","database","validation","odps"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}