apache/superset · error · AsyncQueryTokenException
Failed to parse token
Error message
Failed to parse token
What it means
AsyncQueryTokenException('Failed to parse token') wraps any exception raised while decoding the async-events JWT cookie with jwt.decode(token, secret, algorithms=['HS256']). It fires when the cookie exists but is not a valid HS256 JWT signed with the configured GLOBAL_ASYNC_QUERIES_JWT_SECRET, or when the decoded payload lacks the 'channel' claim. The underlying exception is logged as a warning with a traceback before re-raising.
Source
Thrown at superset/async_events/async_query_manager.py:279
).hexdigest()
return f"guest-{digest}"
def parse_channel_id_from_request(self, req: Request) -> str:
# pylint: disable=import-outside-toplevel
from superset import security_manager
if guest_user := security_manager.get_current_guest_user_if_guest():
return self.get_guest_user_channel_id(guest_user)
token = req.cookies.get(self._jwt_cookie_name)
if not token:
raise AsyncQueryTokenException("Token not preset")
try:
return jwt.decode(token, self._jwt_secret, algorithms=["HS256"])["channel"]
except Exception as ex:
logger.warning("Parse jwt failed", exc_info=True)
raise AsyncQueryTokenException("Failed to parse token") from ex
def init_job(self, channel_id: str, user_id: Optional[int]) -> dict[str, Any]:
job_id = str(uuid.uuid4())
self._register_cancellable_job(job_id, channel_id, user_id)
return build_job_metadata(
channel_id, job_id, user_id, status=self.STATUS_PENDING
)
def _job_registry_key(self, job_id: str) -> str:
return f"{self._stream_prefix}{self._JOB_REGISTRY_PREFIX}{job_id}"
def _register_cancellable_job(
self, job_id: str, channel_id: str, user_id: Optional[int]
) -> None:
"""
Persist the identity a later cancel request must match. Keyed by
``job_id`` (also the Celery task id — see ``submit_chart_data_job``) so
the cancel endpoint can authorize the caller against the job's originalView on GitHub (pinned to f4587218dd)
Solutions
- Have the user clear the Superset cookies (or log out/in) so a fresh token is issued with the current secret.
- If the secret was rotated, ensure ALL webserver and worker pods share the new value; inconsistent secrets across replicas cause intermittent failures.
- Give each environment a distinct GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME to avoid cookie collisions between instances on the same domain.
- Check the webserver log line 'Parse jwt failed' for the underlying jwt error (ExpiredSignature, InvalidSignature, DecodeError) to pick the right fix.
Example fix
# deployment fix: unique cookie names per environment # before GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = "async-token" # (dev and prod on same domain overwrite each other's cookies) # after GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = "async-token-prod"
Defensive patterns
Strategy: try-catch
Validate before calling
import jwt
def token_is_decodable(token: str, secret: str) -> bool:
try:
jwt.decode(token, secret, algorithms=["HS256"])
return True
except Exception:
return False Try / catch
except AsyncQueryTokenException as ex:
if "Failed to parse token" in str(ex):
# instruct client to clear cookies / re-login; check server log for jwt reason
return response_401() Prevention
- Use per-environment cookie names to avoid cross-instance cookie collisions.
- Rotate secrets with a forced logout so stale cookies are never decoded.
- Watch the 'Parse jwt failed' warning log to distinguish expiry vs signature failures.
When it happens
Trigger: The GAQ JWT secret was changed/rotated so cookies issued under the old secret no longer verify; a stale cookie from a different Superset instance or environment (e.g. port 8088 dev vs prod sharing localhost); the cookie was truncated or mangled by a proxy; an expired token (exp claim passed); a hand-crafted cookie value.
Common situations: Rotating the JWT secret during a security push and forgetting that browsers hold old cookies; running multiple Superset versions side by side on the same host so cookies collide on name; deployments behind TLS terminators or CDN that rewrite cookies; clock skew making tokens appear expired.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Token not preset
- Please provide a JWT secret at least 32 bytes long
- Unsupported cache backend configuration
- Cache backends (CACHE_CONFIG, DATA_CACHE_CONFIG) must be con
- Job not found or already completed
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/b1adc1a42359c48f.
Report an issue: GitHub.