{"record":{"id":"52bbd06eac8a97b9","repo":"yt-dlp/yt-dlp","slug":"invalid-format-sort-string-item-given-by-extra","errorCode":null,"errorMessage":"Invalid format sort string \"{item}\" given by extractor","messagePattern":"Invalid format sort string \"(.+?)\" given by extractor","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/utils/_utils.py","lineNumber":5537,"sourceCode":"                'reverse': reverse,\n                'closest': False if limit is None else closest,\n                'limit_text': limit_text,\n                'limit': limit}\n            if field in self.settings:\n                self.settings[field].update(data)\n            else:\n                self.settings[field] = data\n\n        sort_list = (\n            tuple(field for field in self.default if self._get_field_setting(field, 'forced'))\n            + (tuple() if params.get('format_sort_force', False)\n                else tuple(field for field in self.default if self._get_field_setting(field, 'priority')))\n            + tuple(self._sort_user) + tuple(sort_extractor) + self.default)\n\n        for item in sort_list:\n            match = re.match(self.regex, item)\n            if match is None:\n                raise ExtractorError(f'Invalid format sort string \"{item}\" given by extractor')\n            field = match.group('field')\n            if field is None:\n                continue\n            if self._get_field_setting(field, 'type') == 'alias':\n                alias, field = field, self._get_field_setting(field, 'field')\n                if self._get_field_setting(alias, 'deprecated'):\n                    self.ydl.deprecated_feature(f'Format sorting alias {alias} is deprecated and may '\n                                                f'be removed in a future version. Please use {field} instead')\n            reverse = match.group('reverse') is not None\n            closest = match.group('separator') == '~'\n            limit_text = match.group('limit')\n\n            has_limit = limit_text is not None\n            has_multiple_fields = self._get_field_setting(field, 'type') == 'combined'\n            has_multiple_limits = has_limit and has_multiple_fields and not self._get_field_setting(field, 'same_limit')\n\n            fields = self._get_field_setting(field, 'field') if has_multiple_fields else (field,)\n            limits = limit_text.split(':') if has_multiple_limits else (limit_text,) if has_limit else tuple()","sourceCodeStart":5519,"sourceCodeEnd":5555,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/utils/_utils.py#L5519-L5555","documentation":"Raised inside FormatSorter when a format-sort item supplied by an extractor (the 'format_sort' field of the info dict, collected as sort_extractor) fails to match the sort-item regex. Every item in the composed sort_list is validated with re.match(self.regex, item); a non-matching string raises ExtractorError('Invalid format sort string \"<item>\" given by extractor'). Items must be a known field, optionally prefixed with +/- and with an optional :limit or ~separator.","triggerScenarios":"A built-in or plugin extractor puts a malformed string (e.g. 'vcodec:', 'proto;', 'quality+') into info['format_sort']; or a yt-dlp version where the field name a plugin uses is not in FormatSorter's field list.","commonSituations":"Third-party/forked extractor plugins that set format_sort without validating; running an outdated yt-dlp whose field set differs from what the extractor expects; hand-edited forks after a FormatSorter refactor.","solutions":["Update yt-dlp - if a built-in extractor emits a bad string this is a bug and gets patched","If you use plugin extractors, update or disable the plugin whose extractor sets format_sort","If you maintain the extractor, emit only valid items: field names from FormatSorter (lang, vcodec, acodec, size, tbr, proto, ext, ...) with optional leading +/-, optional ~closest marker and :limit, e.g. '+vcodec:h264' or 'res~720'","Report with yt-dlp -v output including the offending item so it can be reproduced"],"exampleFix":"# before (extractor code)\n'format_sort': ['vcodec:'],  # ExtractorError: Invalid format sort string \"vcodec:\" given by extractor\n\n# after\n'format_sort': ['+vcodec', 'res'],","handlingStrategy":"validation","validationCode":"from yt_dlp.utils import FormatSorter\nsort_re = FormatSorter(None).regex  # reuse the exact validation regex\n\ndef valid_sort_item(item: str) -> bool:\n    return sort_re.match(item) is not None","typeGuard":null,"tryCatchPattern":"# as an yt-dlp user you cannot fix extractor-supplied sort strings;\n# catch and continue with other videos\nfrom yt_dlp.utils import ExtractorError\ntry:\n    ydl.download([url])\nexcept ExtractorError as e:\n    if 'Invalid format sort string' in str(e):\n        logger.error('extractor bug for %s; update yt-dlp', url)","preventionTips":["Keep yt-dlp updated so built-in extractors emit only valid format_sort items","Extractor authors: build format_sort from FormatSorter's known field names, never free-form strings","Plugin extractors: add tests asserting every format_sort item matches FormatSorter.regex","Pin plugin versions known to work with your yt-dlp release"],"tags":["format-sort","format-selection","extractor","configuration"],"backgroundTag":"invalid-sort-order-spec","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}