felixse/FluentTerminal · error · SaveTextFileException
Failed to save the file.
Error message
Failed to save the file.
What it means
Thrown by TrayProcessCommunicationService.SaveTextFileAsync when the system-tray (full-trust) side process returns a CommonResponse with Success == false and no Error string. The UWP app cannot write arbitrary files directly, so it delegates to the Win32 tray process via an AppService ValueSet; on failure with a blank error it substitutes the generic 'Failed to save the file.' message.
Source
Thrown at FluentTerminal.App.Services/Implementation/TrayProcessCommunicationService.cs:81
var response = await GetResponseAsync<StringValueResponse>(new GetUserNameRequest()).ConfigureAwait(false);
if (response.Success)
{
_userName = response.Value;
}
return _userName;
}
public async Task SaveTextFileAsync(string path, string content)
{
var response =
await GetResponseAsync<CommonResponse>(new SaveTextFileRequest {Path = path, Content = content})
.ConfigureAwait(false);
if (!response.Success)
{
throw new SaveTextFileException(string.IsNullOrEmpty(response.Error)
? "Failed to save the file."
: response.Error);
}
}
public async Task<string> ReadTextFileAsync(string path)
{
var response = await GetResponseAsync<StringValueResponse>(new ReadTextFileRequest { Path = path }).ConfigureAwait(false);
if (!response.Success)
{
throw new ReadTextFileException(string.IsNullOrWhiteSpace(response.Error) ? "Failed to read the file." : response.Error);
}
return response.Value;
}
public async Task<string> GetSshConfigDirAsync()View on GitHub (pinned to ba83ec485e)
Solutions
- Verify the target path is writable by the user and is not a directory, read-only file, or locked file.
- Check the tray-side SaveTextFile handler to ensure it sets response.Error from the caught exception so the real cause is surfaced.
- Run the app/tray with appropriate privileges if writing to a protected location.
- Confirm the tray process is alive and the AppService connection is open (a dead tray yields no usable response).
Example fix
// before
throw new SaveTextFileException(string.IsNullOrEmpty(response.Error) ? "Failed to save the file." : response.Error);
// after (tray side) - always populate Error
// catch (Exception ex) { return new CommonResponse { Success = false, Error = ex.Message }; } Defensive patterns
Strategy: try-catch
Validate before calling
// Validate path writability before delegating to the tray.
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("path required");
var dir = System.IO.Path.GetDirectoryName(path);
if (!System.IO.Directory.Exists(dir)) throw new System.IO.DirectoryNotFoundException(dir); Try / catch
try { await tray.SaveTextFileAsync(path, content); }
catch (SaveTextFileException ex) { logger.Warn(ex, "save failed"); notifyUser(ex.Message); } Prevention
- Pre-check the target directory exists and is writable before saving.
- Ensure the tray-side handler always populates response.Error so the real cause surfaces.
- Confirm the tray process is running before issuing file requests.
- Avoid saving to system-protected paths without elevation.
When it happens
Trigger: SaveTextFileRequest is sent over the AppService connection; the tray handler catches an IOException/UnauthorizedAccessException and returns Success=false. If the handler does not populate response.Error, the default message is used.
Common situations: Target path is read-only or denied by ACL; path points to a directory or invalid drive; disk full; tray process running with insufficient privileges for the chosen location; file locked by another process.
Related errors
AI-assisted analysis of felixse/FluentTerminal@ba83ec485e (2026-08-13).
Data as JSON: /api/errors/9e3863b8ee165943.
Report an issue: GitHub.