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

  1. Verify the target path is writable by the user and is not a directory, read-only file, or locked file.
  2. Check the tray-side SaveTextFile handler to ensure it sets response.Error from the caught exception so the real cause is surfaced.
  3. Run the app/tray with appropriate privileges if writing to a protected location.
  4. 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

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.