{"record":{"id":"6f90c522305bc723","repo":"yt-dlp/yt-dlp","slug":"unknown-graphql-api-error","errorCode":null,"errorMessage":"Unknown GraphQL API error","messagePattern":"Unknown GraphQL API error","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/telewebion.py","lineNumber":82,"sourceCode":"        variables: dict[str, tuple[str, str]] | None = None,\n        note='Downloading GraphQL JSON metadata',\n    ):\n        parameters = ''\n        if variables:\n            parameters = ', '.join(f'${name}: {type_}' for name, (type_, _) in variables.items())\n            parameters = f'({parameters})'\n\n        result = self._download_json('https://graph.telewebion.ir/graphql', video_id, note, data=json.dumps({\n            'operationName': operation,\n            'query': f'query {operation}{parameters} @cacheControl(maxAge: 60) {{{query}\\n}}\\n',\n            'variables': {name: value for name, (_, value) in (variables or {}).items()},\n        }, separators=(',', ':')).encode(), headers={\n            'Content-Type': 'application/json',\n            'Accept': 'application/json',\n        })\n        if not result or traverse_obj(result, 'errors'):\n            message = ', '.join(traverse_obj(result, ('errors', ..., 'message', {str})))\n            raise ExtractorError(message or 'Unknown GraphQL API error')\n\n        return result['data']\n\n    def _real_extract(self, url):\n        video_id = self._match_id(url)\n        if not video_id.startswith('0x'):\n            video_id = hex(int(video_id))\n\n        episode_data = self._call_graphql_api('getEpisodeDetail', video_id, textwrap.dedent('''\n            queryEpisode(filter: {EpisodeID: $EpisodeId}, first: 1) {\n              title\n              program {\n                ProgramID\n                title\n              }\n              image\n              view_count\n              duration","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/telewebion.py#L64-L100","documentation":"Thrown by TelewebionIE._call_graphql_api when the POST to https://graph.telewebion.ir/graphql returns a falsy body or a body containing an 'errors' array. Message text is joined from errors[*].message; if the errors carry no string messages (or the result is empty), the fallback message 'Unknown GraphQL API error' is raised. This is the GraphQL-standard error envelope surfaced as an ExtractorError.","triggerScenarios":"Any GraphQL operation (getEpisodeDetail etc.) failing server-side: unknown/deleted episode id passed as $EpisodeId, invalid query shape after the site changed its schema, rate limiting, or an empty 200 response. traverse_obj(result, 'errors') truthy OR result falsy both land here.","commonSituations":"Episode ids from old links after Telewebion re-indexed content (the extractor converts decimal ids to hex — a stale id maps to nothing); schema changes on the GraphQL endpoint; IP-based throttling of the graph host.","solutions":["Read the joined error messages — Telewebion's API usually states the exact reason (e.g. episode not found).","Verify the episode still exists at telewebion.ir in a browser; if removed, the id is permanently dead.","Update yt-dlp in case the GraphQL query shape was updated to match a schema change.","If throttling is suspected, slow down and retry later from a non-rate-limited network."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def is_graphql_error(e: Exception) -> bool:\n    return isinstance(e, ExtractorError) and ('GraphQL' in str(e) or 'telewebion' in str(e).lower())","tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    msg = str(e)\n    if 'Unknown GraphQL API error' in msg or 'episode' in msg.lower():\n        log.info('telewebion API rejected the request: %s', msg)\n    else:\n        raise","preventionTips":["Validate episode links in a browser before batch archiving — reindexed ids fail permanently.","Log the joined GraphQL messages; they usually name the exact server-side reason.","Throttle requests to graph.telewebion.ir to avoid throttle-driven error envelopes."],"tags":["yt-dlp","extractor","telewebion","graphql","api-error"],"backgroundTag":"graphql-api-error","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}