{"record":{"id":"7a7a11545faf3c4f","repo":"apache/superset","slug":"cache-backends-cache-config-data-cache-config-m","errorCode":null,"errorMessage":"Cache backends (CACHE_CONFIG, DATA_CACHE_CONFIG) must be configured and non-null in order to enable async queries","messagePattern":"Cache backends \\(CACHE_CONFIG, DATA_CACHE_CONFIG\\) must be configured and non-null in order to enable async queries","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"superset/async_events/async_query_manager.py","lineNumber":133,"sourceCode":"        super().__init__()\n        self._cache: Optional[BaseCache] = None\n        self._stream_prefix: str = \"\"\n        self._stream_limit: Optional[int]\n        self._stream_limit_firehose: Optional[int]\n        self._jwt_cookie_name: str = \"\"\n        self._jwt_cookie_secure: bool = False\n        self._jwt_cookie_domain: Optional[str]\n        self._jwt_cookie_samesite: Optional[Literal[\"None\", \"Lax\", \"Strict\"]] = None\n        self._jwt_secret: str\n        self._jwt_expiration_seconds: int = 0\n        self._load_chart_data_into_cache_job: Any = None\n        # pylint: disable=invalid-name\n\n    def init_app(self, app: Flask) -> None:\n        cache_type = app.config.get(\"CACHE_CONFIG\", {}).get(\"CACHE_TYPE\")\n        data_cache_type = app.config.get(\"DATA_CACHE_CONFIG\", {}).get(\"CACHE_TYPE\")\n        if cache_type in [None, \"null\"] or data_cache_type in [None, \"null\"]:\n            raise Exception(  # pylint: disable=broad-exception-raised\n                \"\"\"\n                Cache backends (CACHE_CONFIG, DATA_CACHE_CONFIG) must be configured\n                and non-null in order to enable async queries\n                \"\"\"\n            )\n\n        self._cache = get_cache_backend(app.config)\n        logger.debug(\"Using GAQ Cache backend as %s\", type(self._cache).__name__)\n\n        if len(app.config[\"GLOBAL_ASYNC_QUERIES_JWT_SECRET\"]) < 32:\n            raise AsyncQueryTokenException(\n                \"Please provide a JWT secret at least 32 bytes long\"\n            )\n\n        self._stream_prefix = app.config[\"GLOBAL_ASYNC_QUERIES_REDIS_STREAM_PREFIX\"]\n        self._stream_limit = app.config[\"GLOBAL_ASYNC_QUERIES_REDIS_STREAM_LIMIT\"]\n        self._stream_limit_firehose = app.config[\n            \"GLOBAL_ASYNC_QUERIES_REDIS_STREAM_LIMIT_FIREHOSE\"","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/async_events/async_query_manager.py#L115-L151","documentation":"AsyncQueryManager.init_app() raises a plain Exception at startup when either CACHE_CONFIG.CACHE_TYPE or DATA_CACHE_CONFIG.CACHE_TYPE is None or 'null'. Global async queries offload chart data requests to Celery and store results in the data cache, so both cache backends must be real (non-null) before the feature can be enabled — a deliberate fail-fast guard during app initialization.","triggerScenarios":"Setting FEATURE_FLAGS = {\"GLOBAL_ASYNC_QUERIES\": True} in superset_config.py while CACHE_CONFIG or DATA_CACHE_CONFIG is missing, set to {\"CACHE_TYPE\": \"null\"}, or still at the default null cache. init_app runs at webserver and worker startup, so the process refuses to boot.","commonSituations":"Minimal dev configs that never configured caching but flipped the GAQ flag on; deployments that disabled caching deliberately (\"CACHE_TYPE\": \"null\") for debugging and later enabled async queries without restoring caches; helm values where cache config keys are misnamed so they land in the wrong config dict.","solutions":["Configure both caches in superset_config.py, e.g. CACHE_CONFIG = {\"CACHE_TYPE\": \"RedisCache\", \"CACHE_URL\": ...} and DATA_CACHE_CONFIG likewise.","Or disable GLOBAL_ASYNC_QUERIES in FEATURE_FLAGS until caching is set up.","After fixing, restart both the webserver and Celery workers — init_app runs in each."],"exampleFix":"# before (superset_config.py)\nFEATURE_FLAGS = {\"GLOBAL_ASYNC_QUERIES\": True}\n# no CACHE_CONFIG / DATA_CACHE_CONFIG -> app fails to start\n\n# after\nfrom celery.schedules import crontab  # (not needed, placeholder import removal)\nCACHE_CONFIG = {\"CACHE_TYPE\": \"RedisCache\", \"CACHE_URL\": \"redis://redis:6379/1\"}\nDATA_CACHE_CONFIG = {\"CACHE_TYPE\": \"RedisCache\", \"CACHE_URL\": \"redis://redis:6379/1\"}\nFEATURE_FLAGS = {\"GLOBAL_ASYNC_QUERIES\": True}","handlingStrategy":"validation","validationCode":"def gaq_ready(cfg: dict) -> bool:\n    for key in (\"CACHE_CONFIG\", \"DATA_CACHE_CONFIG\"):\n        if cfg.get(key, {}).get(\"CACHE_TYPE\") in (None, \"null\"):\n            return False\n    return True\n\nassert gaq_ready(app.config) or not app.config[\"FEATURE_FLAGS\"].get(\"GLOBAL_ASYNC_QUERIES\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate the GLOBAL_ASYNC_QUERIES feature flag on cache configuration in your config management.","Smoke-test `superset run` in CI with the production config to catch startup guards before deploy."],"tags":["configuration","startup","async-queries","cache","redis"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}