dotnet/wpf · error · ArgumentException
SR.Format(SR.CustomDictionaryFailedToLoadDictionaryUri…
Error message
SR.Format(SR.CustomDictionaryFailedToLoadDictionaryUri, lexiconFilePath)
What it means
WinRTSpellerInterop.LoadDictionaryImpl throws ArgumentException when the custom dictionary (lexicon) file does not exist at the supplied path. WPF spell-checking custom dictionaries must be a real file on disk before being registered, so the API fails fast with a message naming the missing path.
Solutions
- Verify the lexicon file exists before adding it: check File.Exists(lexiconFilePath) and create or fix the path if false.
- Ensure the dictionary file is included in the project as Content with CopyToOutputDirectory set, so it ships with the app.
- Use an absolute path (Path.Combine(AppContext.BaseDirectory, "dictionary.lex")) instead of a relative one.
- Catch ArgumentException around the dictionary registration and fall back to default spell-checking.
Example fix
// before
speller.CustomDictionaries.Add(new Uri(relativeLexPath));
// after
string lexPath = Path.Combine(AppContext.BaseDirectory, "custom.lex");
if (!File.Exists(lexPath))
throw new FileNotFoundException("Custom dictionary missing", lexPath);
speller.CustomDictionaries.Add(new Uri(lexPath)); Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrEmpty(lexiconFilePath) || !File.Exists(lexiconFilePath))
throw new FileNotFoundException($"Lexicon not found: {lexiconFilePath}"); Try / catch
try { speller.CustomDictionaries.Add(dictUri); }
catch (ArgumentException ex) { Log.Warn($"Dictionary skipped: {ex.Message}"); } Prevention
- Always ship the lexicon as Content with CopyToOutputDirectory=CopyIfNewer
- Resolve to absolute paths via AppContext.BaseDirectory before registering
- Check File.Exists before every Add, not only at startup
- Log the resolved path to catch CWD differences between dev and production
When it happens
Trigger: Calling SpellingReform/CustomDictionaries.Add (via LoadDictionary -> LoadDictionaryImpl) with a lexiconFilePath for which System.IO.File.Exists returns false — e.g. a typo'd path, a file deleted after registration, or a path in a location the process cannot see.
Common situations: Deploying an app that ships a .lex file but the file wasn't copied to the output directory; using a relative path whose current working directory differs; referencing a dictionary in a user profile that doesn't exist under another account; cleaning/publishing removing content files.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Can only countersign parts with Digital Signature…
- Duplicates not allowed - signature part already exists.
- ExtendedProperty is already part of the…
- GUID cannot be empty.
- InvalidMatrixContainsInfinity
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/92326115d59ad0cf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/WinRTSpellerInterop.cs:430
///
/// If no culture is specified in the first line of <paramref name="lexiconFilePath"/>
/// in the format #LID nnnn (where nnnn = decimal LCID of the culture), then invariant
/// culture is returned.
/// </returns>
/// <remarks>
/// At the end of this method, we guarantee that <paramref name="lexiconFilePath"/>
/// can be reclaimed (i.e., potentially deleted) by the caller.
/// </remarks>
private Tuple<string, string> LoadDictionaryImpl(string lexiconFilePath)
{
if (_isDisposed)
{
return new Tuple<string, string>(null, null);
}
if (!File.Exists(lexiconFilePath))
{
throw new ArgumentException(SR.Format(SR.CustomDictionaryFailedToLoadDictionaryUri, lexiconFilePath));
}
bool fileCopied = false;
string lexiconPrivateCopyPath = null;
try
{
CultureInfo culture = null;
// Read the first line of the file and detect culture, if specified
using (FileStream stream = new FileStream(lexiconFilePath, FileMode.Open, FileAccess.Read))
{
string line = null;
using (StreamReader reader = new StreamReader(stream))
{
line = reader.ReadLine();
culture = WinRTSpellerInterop.TryParseLexiconCulture(line);
}View on GitHub (pinned to 81131a70a4)