Error Handling
Relevant source files
The following files were used as context for generating this wiki page:Error handling in Scripty is managed on two distinct layers: the Rust backend (Tauri Core) and the JavaScript frontend (React). The backend uses Rust's standard Result<T, E> enum to handle operations that can fail, such as file I/O or command execution. These results are then passed to the frontend, where async/await calls are wrapped in try...catch blocks. User-facing errors are presented through native dialog boxes provided by the @tauri-apps/plugin-dialog plugin, ensuring a consistent and clear user experience.
This dual-layer approach separates system-level error management from user interaction. The backend is responsible for identifying and reporting the failure, while the frontend is responsible for catching the report and notifying the user in a friendly manner.
Backend Error Handling (Rust)
The Rust backend handles errors by returning a Result type from its Tauri commands. For operations that can fail, the function signature typically returns a Result<SuccessType, ErrorType>. In Scripty, the ErrorType is almost always a String, providing a descriptive error message that can be easily displayed on the frontend.
Sources: src-tauri/src/lib.rs
Key Functions and Patterns
The primary pattern is to use Rust's match expressions or map_err to convert specific error types (like std::io::Error) into a generic String. This string is what the frontend receives in the catch block of a rejected JavaScript Promise.
| Function | Description | Return Type |
|---|---|---|
extract_syspwsh | Extracts an embedded executable. Maps std::io::Error to a String on failure. | Result<PathBuf, String> |
run_sys_terminal | Runs a command as the SYSTEM user. Returns an Err(String) if the command status is not successful. | Result<(), String> |
read_ps1 | Reads a .ps1 file. Returns an Err(String) if fs::read_to_string fails. | Result<(String, String), String> |
open_admin_terminal | Spawns an elevated PowerShell process. Uses .expect() which will panic and crash the thread on failure. | () |
Sources: src-tauri/src/lib.rs:11-66
File Read Error Flow
The read_ps1 command demonstrates the standard error handling flow. It attempts to read a file to a string and, on failure, returns a formatted error message.
// src-tauri/src/lib.rs:60-65
#[tauri::command]
fn read_ps1(path: String) -> Result<(String, String), String> {
match fs::read_to_string(&path) {
Ok(content) => Ok((path, content)),
Err(_e) => Err(format!("Failed to resolve the .ps1 file")),
}
}
Sources: src-tauri/src/lib.rs:60-65
This diagram shows the logic within the Rust backend for the read_ps1 command.
Sources: src-tauri/src/lib.rs:60-65
Unrecoverable Errors
In some cases, like spawning a process in open_admin_terminal, the code uses .expect(). This is a deliberate choice for situations where failure is not considered a recoverable error from the application's perspective, and a panic is acceptable. This will terminate the backend thread handling the request.
// src-tauri/src/lib.rs:41-42
.spawn()
.expect("Failed to start elevated PowerShell");
Sources: src-tauri/src/lib.rs:41-42
Frontend Error Handling (React)
The frontend uses try...catch blocks to handle potential errors from invoke calls to the Tauri backend. When a Rust command returns an Err, the JavaScript Promise returned by invoke is rejected, and the catch block is executed.
Sources: src/components/Form/Form.jsx, src/components/DetailView/DetailView.jsx
Displaying Errors to the User
The primary mechanism for displaying errors is the message function from the @tauri-apps/plugin-dialog library. This function shows a native modal dialog to the user.
This sequence diagram illustrates how the frontend handles a file-not-found error when a user tries to add a new script.
The implementation in Form.jsx shows this flow clearly.
// src/components/Form/Form.jsx:25-31
try {
const [filename, content] = await invoke("read_ps1", { path: selected });
file = filename;
end = content;
} catch (err) {
await message("File nicht gefunden", {
title: "ES/Script",
kind: "error",
});
}
Sources: src/components/Form/Form.jsx:25-31
User Confirmation Dialogs
In addition to error messages, the application uses the ask dialog for actions that require user confirmation, such as deleting a script. This is a form of proactive error prevention, ensuring the user does not perform a destructive action by mistake. If the user cancels the action, the function returns early, preventing the removeItem call.
// src/components/DetailView/DetailView.jsx:36-46
const deleteItem = async () => {
const answer = await ask("Are you sure you want to delete this script?", {
title: "(S)cripty",
kind: "warning",
});
if (answer === true) {
removeItem(selectedItem.id);
setIsVisible(false);
} else {
return;
}
};