{"record":{"id":"c548fa5c9ffd15cc","repo":"ytdl-org/youtube-dl","slug":"missing-title-field-in-extractor-result","errorCode":null,"errorMessage":"Missing \"title\" field in extractor result","messagePattern":"Missing \"title\" field in extractor result","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/YoutubeDL.py","lineNumber":1651,"sourceCode":"                    upload_date = datetime.datetime.utcfromtimestamp(info_dict[ts_key])\n                    info_dict[date_key] = compat_str(upload_date.strftime('%Y%m%d'))\n                except (ValueError, OverflowError, OSError):\n                    pass\n\n        # Auto generate title fields corresponding to the *_number fields when missing\n        # in order to always have clean titles. This is very common for TV series.\n        if final:\n            for field in ('chapter', 'season', 'episode'):\n                if info_dict.get('%s_number' % field) is not None and not info_dict.get(field):\n                    info_dict[field] = '%s %d' % (field.capitalize(), info_dict['%s_number' % field])\n\n    def process_video_result(self, info_dict, download=True):\n        assert info_dict.get('_type', 'video') == 'video'\n\n        if 'id' not in info_dict:\n            raise ExtractorError('Missing \"id\" field in extractor result')\n        if 'title' not in info_dict:\n            raise ExtractorError('Missing \"title\" field in extractor result')\n\n        def report_force_conversion(field, field_not, conversion):\n            self.report_warning(\n                '\"%s\" field is not %s - forcing %s conversion, there is an error in extractor'\n                % (field, field_not, conversion))\n\n        def sanitize_string_field(info, string_field):\n            field = info.get(string_field)\n            if field is None or isinstance(field, compat_str):\n                return\n            report_force_conversion(string_field, 'a string', 'string')\n            info[string_field] = compat_str(field)\n\n        def sanitize_numeric_fields(info):\n            for numeric_field in self._NUMERIC_FIELDS:\n                field = info.get(numeric_field)\n                if field is None or isinstance(field, compat_numeric_types):\n                    continue","sourceCodeStart":1633,"sourceCodeEnd":1669,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/YoutubeDL.py#L1633-L1669","documentation":"Raised by xpath_text when the matched element exists but has no text content (node.text is None), no default was given, and fatal=True. Distinct from 'Could not find XML element': here the XPath matched an empty element (<Title/> or <Title></Title>), so the node exists but its text is absent.","triggerScenarios":"xpath_text(node, xpath, fatal=True) where the document contains the element empty. Common with optional API fields serialized as empty tags, or elements that carry only attributes/children and no text.","commonSituations":"Site API starts returning empty tags for missing values instead of omitting them; extractors that treat such fields as mandatory; namespace/structure changes where the XPath matches a wrapper element whose text moved to a child.","solutions":["Pass default='' (or another sentinel) or fatal=False so empty text returns the default/None instead of raising.","Verify the XPath points at the leaf element that actually carries text, not a container.","Update youtube-dl / yt-dlp if this comes from a built-in extractor reacting to a schema change.","When iterating many items, catch ExtractorError per item and skip only the affected entry."],"exampleFix":"# before\nduration = xpath_text(item, 'duration', fatal=True)\n\n# after\nduration = xpath_text(item, 'duration', default=None)\nif duration is not None:\n    duration = parse_duration(duration)","handlingStrategy":"validation","validationCode":"from youtube_dl.utils import xpath_element\n\n# pre-check text instead of letting xpath_text raise\nnode = xpath_element(doc, xpath, fatal=False, default=None)\ntext = node.text if (node is not None and node.text is not None) else None\nif text is None:\n    text = fallback","typeGuard":null,"tryCatchPattern":"from youtube_dl.utils import ExtractorError, xpath_text\ntry:\n    val = xpath_text(doc, '//Title', name='title', fatal=True)\nexcept ExtractorError as e:\n    if \"element's text\" in str(e):\n        val = ''  # element exists but is empty — treat as empty string\n    else:\n        raise","preventionTips":["Use default='' for fields where an empty element is acceptable.","Point XPaths at leaf nodes that carry text, not wrapper elements.","Distinguish this error from 'Could not find XML element': here the node matched but had no text."],"tags":["xml","xpath","extractor","empty-value"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}