{"record":{"id":"f0f57beae972bfdb","repo":"ungoogled-software/ungoogled-chromium","slug":"path-relative-path-contains-the-file-index-has","errorCode":null,"errorMessage":"Path \"{relative_path}\" contains the file index hash delimiter \"{_INDEX_HASH_DELIMITER}\"","messagePattern":"Path \"(.+?)\" contains the file index hash delimiter \"(.+?)\"","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"utils/domain_substitution.py","lineNumber":218,"sourceCode":"    if not regex_path.exists():\n        raise FileNotFoundError(regex_path)\n    if not files_path.exists():\n        raise FileNotFoundError(files_path)\n    if domainsub_cache and domainsub_cache.exists():\n        raise FileExistsError(domainsub_cache)\n    resolved_tree = source_tree.resolve()\n    regex_pairs = DomainRegexList(regex_path).regex_pairs\n    fileindex_content = io.BytesIO()\n    with tarfile.open(str(domainsub_cache), f'w:{domainsub_cache.suffix[1:]}',\n                      compresslevel=1) if domainsub_cache else open(\n                          os.devnull, 'w', encoding=ENCODING) as cache_tar:\n        for relative_path in filter(len, files_path.read_text().splitlines()):\n            if _INDEX_HASH_DELIMITER in relative_path:\n                if domainsub_cache:\n                    # Cache tar will be incomplete; remove it for convenience\n                    cache_tar.close()\n                    domainsub_cache.unlink()\n                raise ValueError(f'Path \"{relative_path}\" contains '\n                                 f'the file index hash delimiter \"{_INDEX_HASH_DELIMITER}\"')\n            path = resolved_tree / relative_path\n            if not path.exists():\n                get_logger().warning('Skipping non-existent path: %s', path)\n                continue\n            if path.is_symlink():\n                get_logger().warning('Skipping path that has become a symlink: %s', path)\n                continue\n            with _update_timestamp(path, set_new=True):\n                crc32_hash, orig_content = _substitute_path(path, regex_pairs)\n            if crc32_hash is None:\n                get_logger().info('Path has no substitutions: %s', relative_path)\n                continue\n            if domainsub_cache:\n                fileindex_content.write(\n                    f'{relative_path}{_INDEX_HASH_DELIMITER}{crc32_hash:08x}\\n'.encode(ENCODING))\n                orig_tarinfo = tarfile.TarInfo(str(Path(_ORIG_DIR) / relative_path))\n                orig_tarinfo.size = len(orig_content)","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/ungoogled-software/ungoogled-chromium/blob/f85e84a480e2e17c103de7013de94320f9a2ba39/utils/domain_substitution.py#L200-L236","documentation":"The file index uses _INDEX_HASH_DELIMITER to separate each path from its hash. apply_substitution() raises ValueError if any relative path in the list contains that delimiter, because the cache file index would become ambiguous. It conveniently removes the partially-written cache tar before raising.","triggerScenarios":"A line in the files list contains the delimiter string within the path portion — e.g. a malformed/hand-edited file index, or a path that literally contains the delimiter characters.","commonSituations":"Manually editing or regenerating the file list with the wrong format; hashing tool producing entries in a different delimiter convention; concatenated entries from a bad script.","solutions":["Fix or regenerate the files list so paths do not contain the delimiter","Remove/rename the offending entry containing the delimiter","Escape or strip the delimiter sequence from the path if it is legitimately part of the filename"],"exampleFix":"// before\nfiles_txt = 'path' + DELIM + 'hash'  # path itself contains DELIM -> ValueError\n// after\nif any(DELIM in p for p in paths):\n    raise ValueError('clean paths before building file index')\nwrite_file_index(paths, hashes)","handlingStrategy":"validation","validationCode":"DELIM = '\\n'  # whatever _INDEX_HASH_DELIMITER is in your data source\nbad = [p for p in file_index_lines if DELIM in p.split(DELIM)[0]]\nif bad:\n    raise ValueError(f'paths contain delimiter: {bad}')","typeGuard":null,"tryCatchPattern":"try:\n    apply_substitution(tree, regexes, files)\nexcept ValueError as e:\n    log.error('Malformed file index entry: %s', e)\n    raise","preventionTips":["Never hand-edit the file index; generate it programmatically","Follow the documented path<delimiter>hash line format","Validate index lines before passing them to the library"],"tags":["validation","file-index","format","substitution"],"backgroundTag":"schema-validation-failed","analyzedSha":"f85e84a480e2e17c103de7013de94320f9a2ba39","analyzedAt":"2026-08-29T10:07:17.606Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}