{"record":{"id":"c73c12b505cc7d04","repo":"yt-dlp/yt-dlp","slug":"invalid-extractor-arg-tab-must-be-one-of","errorCode":null,"errorMessage":"Invalid extractor-arg \"tab\". Must be one of {\", \".join(self._TABS)}","messagePattern":"Invalid extractor-arg \"tab\"\\. Must be one of (.+?)","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/rokfin.py","lineNumber":355,"sourceCode":"        },\n    }]\n\n    _TABS = {\n        'new': 'posts',\n        'top': 'top',\n        'videos': 'video',\n        'podcasts': 'audio',\n        'streams': 'stream',\n        'stacks': 'stack',\n    }\n\n    def _real_initialize(self):\n        self._validate_extractor_args()\n\n    def _validate_extractor_args(self):\n        requested_tabs = self._configuration_arg('tab', None)\n        if requested_tabs is not None and (len(requested_tabs) > 1 or requested_tabs[0] not in self._TABS):\n            raise ExtractorError(f'Invalid extractor-arg \"tab\". Must be one of {\", \".join(self._TABS)}', expected=True)\n\n    def _entries(self, channel_id, channel_name, tab):\n        pages_total = None\n        for page_n in itertools.count(0):\n            if tab in ('posts', 'top'):\n                data_url = f'{_API_BASE_URL}user/{channel_name}/{tab}?page={page_n}&size=50'\n            else:\n                data_url = f'{_API_BASE_URL}post/search/{tab}?page={page_n}&size=50&creator={channel_id}'\n            metadata = self._download_json(\n                data_url, channel_name,\n                note=f'Downloading video metadata page {page_n + 1}{format_field(pages_total, None, \" of %s\")}')\n\n            yield from self._get_video_data(metadata)\n            pages_total = int_or_none(metadata.get('totalPages')) or None\n            is_last = metadata.get('last')\n            if is_last or (page_n > pages_total if pages_total else is_last is not False):\n                return\n","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/rokfin.py#L337-L373","documentation":"Rokfin's channel extractor validates the 'tab' extractor-arg in _validate_extractor_args before any network request: the argument must be a single value from the allowed set (the _TABS keys: videos, podcasts, streams, stacks). Passing more than one tab or an unknown name raises this immediately with expected=True.","triggerScenarios":"Invoking a https://rokfin.com/@<channel> URL with --extractor-args where tab is repeated ('tab=videos;tab=streams' yields len > 1) or the value is not in _TABS (e.g. 'tab=all', 'tab=top', 'tab=live').","commonSituations":"Guessing tab names from the website navigation; copy-pasting multi-value extractor-arg syntax from other extractors; shell quoting that splits the argument into multiple values; scripts templating tab names from user input.","solutions":["Use exactly one allowed value: --extractor-args 'rokfinchannel:tab=videos' (or podcasts, streams, stacks)","Pass only one tab per invocation; run the command again for each additional tab","Check the value against the allowed list printed in the error message itself","Update yt-dlp — new tabs are added to _TABS over time"],"exampleFix":"# before\nyt-dlp --extractor-args \"rokfinchannel:tab=videos;tab=streams\" \"https://rokfin.com/@Styxhexenhammer666\"\n# after\nyt-dlp --extractor-args \"rokfinchannel:tab=videos\" \"https://rokfin.com/@Styxhexenhammer666\"\nyt-dlp --extractor-args \"rokfinchannel:tab=streams\" \"https://rokfin.com/@Styxhexenhammer666\"","handlingStrategy":"validation","validationCode":"ROKFIN_TABS = ('videos', 'podcasts', 'streams', 'stacks')\n\ndef build_rokfin_args(tabs):\n    assert len(tabs) == 1, 'pass exactly one tab'\n    assert tabs[0] in ROKFIN_TABS, f'tab must be one of {ROKFIN_TABS}'\n    return ['--extractor-args', f'rokfinchannel:tab={tabs[0]}']","typeGuard":"def is_valid_rokfin_tab(tab: str) -> bool:\n    return tab in {'videos', 'podcasts', 'streams', 'stacks'}","tryCatchPattern":null,"preventionTips":["Take allowed tab values from the extractor source/docs (_TABS), not from the website nav","Pass a single tab= per invocation and loop over tabs in your script","Whitelist extractor-args in wrappers that forward user input"],"tags":["configuration","extractor-args","argument-validation","rokfin"],"backgroundTag":"invalid-argument-value","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}