{"record":{"id":"895b68c1f4b74261","repo":"ytdl-org/youtube-dl","slug":"s-said-s-895b68","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/nexx.py","lineNumber":145,"sourceCode":"                    webpage):\n                entries.append(\n                    'https://api.nexx.cloud/v3/%s/videos/byid/%s'\n                    % (domain_id, video_id))\n\n        # TODO: support more embed formats\n\n        return entries\n\n    @staticmethod\n    def _extract_url(webpage):\n        return NexxIE._extract_urls(webpage)[0]\n\n    def _handle_error(self, response):\n        status = int_or_none(try_get(\n            response, lambda x: x['metadata']['status']) or 200)\n        if 200 <= status < 300:\n            return\n        raise ExtractorError(\n            '%s said: %s' % (self.IE_NAME, response['metadata']['errorhint']),\n            expected=True)\n\n    def _call_api(self, domain_id, path, video_id, data=None, headers={}):\n        headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'\n        result = self._download_json(\n            'https://api.nexx.cloud/v3/%s/%s' % (domain_id, path), video_id,\n            'Downloading %s JSON' % path, data=urlencode_postdata(data),\n            headers=headers)\n        self._handle_error(result)\n        return result['result']\n\n    def _extract_free_formats(self, video, video_id):\n        stream_data = video['streamdata']\n        cdn = stream_data['cdnType']\n        assert cdn == 'free'\n\n        hash = video['general']['hash']","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/nexx.py#L127-L163","documentation":"Raised by NexxIE._handle_error when an api.nexx.cloud v3 response carries metadata.status outside 200-299. The message forwards the API's own metadata.errorhint verbatim (prefixed by the IE name). It is expected=True, so it maps a clean API-level failure to an ExtractorError.","triggerScenarios":"Any _call_api POST/GET to https://api.nexx.cloud/v3/<domain_id>/<path> whose JSON has metadata.status >= 300 or < 200; the errorhint string is surfaced to the user.","commonSituations":"Wrong/stale domain_id extracted from the embedding page (API rejects it); videos deleted or unpublished on the Nexx side; API contract changes after the extractor was written.","solutions":["Read the errorhint — it is Nexx's own explanation (unknown domain, missing resource, expired token) and names the actual problem.","Update youtube-dl / yt-dlp; domain-id extraction drift is the usual root cause.","Verify the video still plays on the customer site embedding Nexx; if withdrawn, there is nothing to fetch."],"exampleFix":"pip install -U yt-dlp   # then retry the embedding page URL","handlingStrategy":"try-catch","validationCode":"import requests\nr = requests.post(f'https://api.nexx.cloud/v3/{domain_id}/{path}', ...).json()\nif not 200 <= int(r.get('metadata', {}).get('status') or 200) < 300:\n    print('nexx api error:', r['metadata'].get('errorhint'))","typeGuard":null,"tryCatchPattern":"except ExtractorError as e:\n    if e.expected and str(e).startswith('Nexx said:'):\n        hint = str(e).split('said:', 1)[1]\n        if 'domain' in hint.lower():\n            report_upstream(url)  # domain_id extraction failed\n        else:\n            mark_unavailable(url, hint)\n    else:\n        raise","preventionTips":["Treat the errorhint as authoritative — it is the API's own diagnosis.","Update yt-dlp when many Nexx embeds fail at once (domain-id drift).","Confirm the embedding page still plays the video before retrying."],"tags":["api-error","extractor","expected-error","streaming-platform"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}