ungoogled-software/ungoogled-chromium · error · UnicodeDecodeError

Unable to decode with any encoding: {path}

Error message

Unable to decode with any encoding: {path}

What it means

_substitute_path() attempts to decode each file with a list of candidate encodings (e.g. UTF-8, then Latin-1). If decoding fails for every encoding, `content` stays unset/empty and a UnicodeDecodeError is raised with this message naming the file.

Source

Thrown at utils/domain_substitution.py:109

    """
    if not os.access(path, os.W_OK):
        # If the patch cannot be written to, it cannot be opened for updating
        print(str(path) + " cannot be opened for writing! Adding write permission...")
        path.chmod(path.stat().st_mode | stat.S_IWUSR)
    with path.open('r+b') as input_file:
        original_content = input_file.read()
        if not original_content:
            return (None, None)
        content = None
        encoding = None
        for encoding in TREE_ENCODINGS:
            try:
                content = original_content.decode(encoding)
                break
            except UnicodeDecodeError:
                continue
        if not content:
            raise UnicodeDecodeError(f'Unable to decode with any encoding: {path}')
        file_subs = 0
        for regex_pair in regex_iter:
            content, sub_count = regex_pair.pattern.subn(regex_pair.replacement, content)
            file_subs += sub_count
        if file_subs > 0:
            substituted_content = content.encode(encoding)
            input_file.seek(0)
            input_file.write(content.encode(encoding))
            input_file.truncate()
            return (zlib.crc32(substituted_content), original_content)
        return (None, None)


def _validate_file_index(index_file, resolved_tree, cache_index_files):
    """
    Validation of file index and hashes against the source tree.
        Updates cache_index_files

View on GitHub (pinned to f85e84a480)

Solutions

  1. Remove the offending path from the file list (files list) used by apply_substitution()
  2. Add the file's actual encoding to the encoding list used for decoding
  3. Re-obtain the file — it may be corrupted or truncated
  4. If the file should be binary, exclude it from domain substitution

Example fix

# before: binary file in substitution list
domsub_apply(source_tree, regexes, files_list)
# after: filter binary files out first
files = [f for f in files_list if not (source_tree / f).suffix in {'.png', '.webp', '.wasm'}]
domsub_apply(source_tree, regexes, files)
Defensive patterns

Strategy: try-catch

Validate before calling

for f in file_list:
    data = (source_tree / f).read_bytes()
    if b'\x00' in data[:1024]:
        raise ValueError(f'binary file in substitution list: {f}')

Try / catch

try:
    apply_substitution(tree, regexes, files)
except UnicodeDecodeError as e:
    log.error('Undecodable file, exclude it from the substitution list: %s', e)
    raise

Prevention

When it happens

Trigger: apply_substitution() iterating the file index reaches a file whose bytes are not valid in any of the configured encodings — a binary file or a file in an unsupported encoding matched by the regex list.

Common situations: Binary resources (images, webp, wasm) ending up in the domain-substitution file list; files saved in UTF-16 or another encoding not in the ENCODING_LIST; corrupted downloads.

Understand the failure class

Related errors


AI-assisted analysis of ungoogled-software/ungoogled-chromium@f85e84a480 (2026-08-29). Data as JSON: /api/errors/156c95e64dd658bd. Report an issue: GitHub.