Skip to content

RenameFile: OSError 'File name too long' from doubled extension in long-filename truncation #767

Description

@garfolino

Plugin

RenameFile

Description

Renaming a scene whose generated filename exceeds max_filename_length (default 255) can produce a filename that is longer than the original and ends in a doubled extension (e.g. ....mp4.mp4), causing the OS rename to fail with OSError: [Errno 63] File name too long on macOS (and the equivalent ENAMETOOLONG elsewhere).

Root cause

In rename_scene() (renamefile.py), the truncate-and-hash fallback appends the file extension onto new_filename before computing/appending the _+MD5-hash suffix, and doesn't reserve space in the length budget for that suffix:

if len(new_filename) > max_filename_length:
    extension_length = len(Path(original_file_path).suffix)
    max_base_filename_length = max_filename_length - extension_length
    truncated_filename = new_filename[:max_base_filename_length]
    hash_suffix = hashlib.md5(new_filename.encode()).hexdigest()
    new_filename = truncated_filename + '_' + hash_suffix + Path(original_file_path).suffix
newFilenameWithExt  = new_filename + Path(original_file_path).suffix

Two bugs:

  1. max_base_filename_length only subtracts the extension length, not the _ + 32-char hash that gets appended afterward — so the "truncated" name can still exceed max_filename_length.
  2. Since new_filename already ends with the extension after truncation, the next line (newFilenameWithExt = new_filename + suffix) appends the extension a second time, producing a name like ....mp4.mp4 and pushing it well past the OS limit.

Reproduction (from a real log)

OSError: [Errno 63] File name too long: '.../Movie-name-(...)-[...].mp4' -> '.../Movie-name-(...)-[...Gagging_a68f3c2a62cef848afd6bb9ef0ff4fc6.mp4.mp4'

The resulting target filename is 292 characters (vs. the configured 255 limit) and ends in .mp4.mp4.

Additional issue

When the rename/move fails, the code logs a clear one-line error (stash.Error(exitMsg)) but then re-raises the OSError, which propagates to the plugin's top-level catch-all and dumps the full Python traceback to the log as well — burying the clear message under noise.


Disclosure: this issue and the accompanying fix (PR to follow) were drafted with LLM (Claude) assistance, based on analysis of a real error log; reviewed and submitted by a human maintainer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions