{"record":{"id":"1a9438bfc55a38a2","repo":"yt-dlp/yt-dlp","slug":"ticket-has-expired","errorCode":null,"errorMessage":"Ticket has expired","messagePattern":"Ticket has expired","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/zan.py","lineNumber":183,"sourceCode":"            self.raise_login_required()\n\n        status = self._download_json(\n            f'{self._BASE_URL}/api/live/{video_id}/getLiveStatus', video_id, headers={\n                'X-Csrf-Token': csrf_token,\n            }, data=urlencode_postdata({\n                'pct': pct,\n                'token': token,\n            }))\n        if not traverse_obj(status, ('isSuccess', {bool})):\n            raise ExtractorError('Unexpected error')\n\n        result = traverse_obj(status, ('result', {dict}))\n        for key, required, error_message in (\n            ('isFinished', False, 'This video is no longer available'),\n            ('canPlay', True, 'Ticket has expired'),\n        ):\n            if traverse_obj(result, (key, {bool})) is not required:\n                raise ExtractorError(error_message, expected=True)\n\n        is_live = not traverse_obj(result, ('isVod', {bool}))\n        release_timestamp = parse_iso8601(self._html_search_meta('open-live-date', webpage))\n        srv_time = traverse_obj(status, ('srvTime', {int_or_none}), default=0)\n\n        if is_live and release_timestamp and srv_time < release_timestamp:\n            start_time = dt.datetime.fromtimestamp(\n                release_timestamp, dt.timezone.utc,\n            ).astimezone().strftime('%Y-%m-%d %H:%M:%S %Z')\n            self.raise_no_formats(\n                f'This livestream is scheduled to start at {start_time}', expected=True)\n\n            return {\n                'id': video_id,\n                'live_status': 'is_upcoming',\n                'release_timestamp': release_timestamp,\n            }\n","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/zan.py#L165-L201","documentation":"Raised by the ZAN extractor when the getLiveStatus result reports canPlay != True: the viewer's ticket for the stream is no longer playable, i.e. it expired. ZAN issues per-viewer playback tickets; once expired, the API refuses playback even though the stream itself may still be running. Marked expected=True.","triggerScenarios":"Loading the page, waiting (or resuming an interrupted download), then calling the API with a ticket whose validity window elapsed; sharing/duplicating a page session whose ticket was already consumed; the check finds canPlay is not True and raises.","commonSituations":"Restarting a download much later using stale session cookies; long-running downloads that re-request playback info after a ticket lapse; ticket tied to a single playback session that was already used.","solutions":["Re-open the event page in the browser (fresh page load issues a new ticket), re-export cookies, and retry promptly","If the event requires a purchase/login, re-authenticate first so a fresh ticket is granted","Retry the extraction immediately after obtaining the fresh session rather than resuming hours later"],"exampleFix":"# before (stale session from an earlier page load)\nyt-dlp --cookies old-cookies.txt \"https://live.zan.com.br/...\"\n\n# after (fresh page visit -> new ticket -> immediate retry)\nyt-dlp --cookies-from-browser chrome \"https://live.zan.com.br/...\"","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from yt_dlp.utils import ExtractorError\ntry:\n    ydl.download([url])\nexcept ExtractorError as e:\n    if 'Ticket has expired' in str(e):\n        refresh_browser_cookies()  # new page visit issues a fresh ticket\n        ydl.download([url])        # retry immediately with the new session\n    else:\n        raise","preventionTips":["Always load the event page right before extraction so the ticket is young","Start long ZAN downloads promptly after opening the page","Keep cookies tied to one playback session; don't reuse them across machines"],"tags":["zan","ticket-expired","live-stream","session"],"backgroundTag":"access-token-expired","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}