SubtitleEdit/subtitleedit · error · FileNotFoundException

Multiple-replace file not found: {path}

Error message

Multiple-replace file not found: {path}

What it means

Thrown by MultipleReplaceLoader.Apply when the multiple-replace rules file does not exist (File.Exists returns false). Apply loads and applies active rules from the file to a subtitle — without the file there is nothing to apply. The exception is a FileNotFoundException with the path as FileName. Note: LoadRules (the lower-level method) does its own File.Exists check via ReadAllText's exception path, but Apply checks first for a clean error.

Source

Thrown at src/seconv/Core/MultipleReplaceLoader.cs:392

            public string ReplaceWith { get; set; } = string.Empty;
            public string? Description { get; set; }
            public bool IsActive { get; set; }
            public string Type { get; set; } = string.Empty;
        }
    }

    /// <summary>
    /// Loads + applies all active rules from <paramref name="path"/> to <paramref name="subtitle"/>.
    /// The file may be the legacy SE4 <c>MultipleSearchAndReplaceGroups</c> XML, or the SE5
    /// GUI's exported <c>.template</c> JSON or <c>.csv</c> (Tools &gt; Multiple replace &gt;
    /// export). Format is chosen by extension, then by content sniffing. Returns the number of
    /// paragraphs whose text was modified.
    /// </summary>
    public static int Apply(Subtitle subtitle, string path)
    {
        if (!File.Exists(path))
        {
            throw new FileNotFoundException($"Multiple-replace file not found: {path}", path);
        }

        var rules = LoadRules(path);
        if (rules.Count == 0)
        {
            return 0;
        }

        // Pre-compile rule patterns once (not per-paragraph):
        //  - RegularExpression rules use the user pattern with RegexOptions.Multiline so ^/$
        //    anchors match at every line boundary, matching the UI (MultipleReplaceViewModel
        //    compiles with Compiled | Multiline).
        //  - Normal (case-insensitive literal) rules compile an escaped, IgnoreCase pattern
        //    so the per-paragraph loop no longer re-escapes and re-parses on every line.
        // A rule with an invalid/empty pattern is left out here so it's skipped entirely.
        var compiledRegex = new Dictionary<Rule, Regex>();
        foreach (var rule in rules)
        {

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Verify the path with File.Exists before calling Apply.
  2. Resolve relative paths to absolute with Path.GetFullPath against the intended base directory.
  3. Check for typos, trailing spaces, or shell-quoting issues in the path argument.

Example fix

// before
MultipleReplaceLoader.Apply(subtitle, rulesPath);

// after
if (!File.Exists(rulesPath))
    throw new FileNotFoundException($"Multiple-replace file not found: {rulesPath}");
MultipleReplaceLoader.Apply(subtitle, rulesPath);
Defensive patterns

Strategy: validation

Validate before calling

if (!File.Exists(path))
    throw new FileNotFoundException($"Multiple-replace file not found: {path}", path);
MultipleReplaceLoader.Apply(subtitle, path);

Type guard

static bool IsReplaceFileReadable(string path) => File.Exists(path);

Try / catch

try { MultipleReplaceLoader.Apply(subtitle, path); }
catch (FileNotFoundException ex) when (ex.Message.Contains("Multiple-replace file not found"))
{ /* report missing rules file, check path/spelling */ }

Prevention

When it happens

Trigger: Calling Apply(subtitle, path) where path does not resolve to an existing file. The path may be a typo, a relative path from the wrong CWD, or reference a file that was moved/deleted.

Common situations: CLI --multiple-replace with a mistyped path; a config referencing a rules file that was moved; a batch script using a relative path that breaks when CWD changes.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/358a49aedc907120. Report an issue: GitHub.