Error Handling
Relevant source files
The following files were used as context for generating this wiki page:Introduction
Error handling in the Discord Live Translator project is implemented through a combination of try...catch blocks, promise rejections, explicit checks, and logging. The strategy is twofold: provide clear, ephemeral feedback to the user in Discord for command-related issues, and log detailed technical errors to the console for developers. For background processes and external service interactions, errors are typically caught, logged, and handled gracefully to prevent the bot from crashing, often by returning an empty result and aborting the current translation task.
The system distinguishes between user-facing errors (e.g., invalid permissions, incorrect command usage) and internal system errors (e.g., failed API calls, file system issues). The Rust-based Speech-to-Text (STT) service employs a "fail-fast" approach, panicking on critical errors like model loading failures. Centralized logging is facilitated by the writeToLog utility, which directs output to both the console and an optional log file.
Core Application Error Handling
Error handling at the application's entry point (app.ts) is designed to catch uncaught exceptions, manage deployment failures, and handle failures in periodic tasks like heartbeats.
Sources: src/app.ts
Global Error Listener
A global error listener is attached to the Discord client instance. Any unhandled 'error' events emitted by the discord.js client are caught and logged directly to the console.
// src/app.ts:68
client.on('error', console.error);
Sources: src/app.ts:68
Command Deployment
During startup, if GUILD_ID is configured, guild-specific slash commands are initialized. The initGuildCommands function wraps the API call in a try...catch block. If the REST API call to Discord fails, the error is caught and logged to the console, preventing the bot from crashing on startup due to deployment issues. A similar pattern exists for global command deployment.
// src/interactions.ts:28-30
} catch (error) {
console.error(error);
}
Sources: src/app.ts:72-77, src/interactions.ts:28-30, src/deploy.ts:10-12
Heartbeat Task
If a HEARTBEAT_URL is configured, the application sends a POST request to that URL every 60 seconds. This process is wrapped in a try...catch block. If the fetch call fails or the response status is not ok, an error is logged to the console, but the application continues to run, allowing it to attempt the heartbeat again on the next interval.
// src/app.ts:86-88
} catch (err) {
console.error('Heartbeat failed:', err);
}
Sources: src/app.ts:79-91
Command Handler Error Flow
Slash command handlers follow a standardized pattern for validating input and handling exceptions. This ensures a consistent user experience and robust error management.
Standard Error Handling Pattern
Most command handlers perform a series of initial checks (guard clauses) to validate the interaction context (e.g., user is in a guild, user is in a voice channel). If a check fails, an ephemeral reply is sent to the user with a specific error message, and the function exits. The main logic is wrapped in a try...catch block. If an unexpected error occurs within this block, it's caught, logged to the console, and a generic error message is sent to the user.
The following diagram illustrates the typical error handling flow within a command handler.
User-Facing Error Messages
Commands provide direct feedback for common, correctable errors. These messages are ephemeral, meaning only the user who executed the command can see them.
| Command | Condition | Error Message | Source File |
|---|---|---|---|
join | User not in a voice channel | You are currently not in a voice channel! :x: | src/commands/join.ts:25-28 |
join | Bot lacks Connect or Speak permissions | The bot is missing permission for your channel to connect and/or speak! :grimacing: | src/commands/join.ts:30-37 |
leave | Bot not in a voice channel | The bot currently is not connected to a voice channel! :x: | src/commands/leave.ts:20-23 |
leave | User not in the same voice channel as the bot | You are currently not in the same voice channel as the bot is in! :x: | src/commands/leave.ts:30-36 |
start | Invalid language code provided | "${targetLanguageRaw}" is not a supported language! Use "/languages" for a list of supported ones. :x: | src/commands/start.ts:32-35 |
| Any | Generic/unexpected error | An error occurred! :grimacing: | src/commands/join.ts:115, src/commands/stop.ts:17 |
Processor and Service Error Handling
The modules responsible for audio processing, translation, and text-to-speech have their own internal error handling to manage failures with external services and file operations.
Audio Recording and Processing
The core translation pipeline, initiated by the join command, involves several steps where errors can occur.
The sequence diagram below shows how an error during the speech-to-text (STT) step is handled.
recordAudio: The audio recording stream pipeline is wrapped in atry...catchblock. If the pipeline fails (e.g., due to a stream error), the error is logged viawriteToLog, and the function returnsundefined.
Sources: src/processors/recordAudio.ts:43-45recognizeRecording: This function checks if the HTTP response from the STT service isok. If not, it logs an error to the console and returns an empty string, effectively stopping the translation process for that utterance. It also includes a.catchblock to log any errors that occur while deleting the temporary audio file.
Sources: src/processors/recognizeRecording.ts:18-21, 25-27translate: Similar torecognizeRecording, this function checks the HTTP status of the response from the translation service. On failure, it logs an error and returns an empty string.
Sources: src/processors/translate.ts:22-25readText: The call to the external Python script for text-to-speech is wrapped in atry...catchblock. Ifexecathrows an error (e.g., script not found, Python error), it is caught and logged to the console.
Sources: src/processors/readText.ts:22-24
Logging Utility
The writeToLog utility provides a centralized way to log messages. It includes its own error handling for file I/O. If LOG_PATH is set and the fs.appendFile operation fails, the error is caught and logged to console.error, preventing a logging failure from crashing the application.
// src/utils/writeToLog.ts:11-13
fs.appendFile(logPath, message + '\n').catch((err) => {
if (err) console.error(err);
});
Sources: src/utils/writeToLog.ts:11-14
Rust STT Service
The Speech-to-Text (STT) service, written in Rust, uses a "fail-fast" error handling strategy by leveraging expect() and unwrap(). This means that if a critical operation fails, the service will panic and terminate.
- Startup: The service panics at startup if the
MODEL_PATHenvironment variable is not set or if the Whisper model fails to load from the specified path. - Runtime: During audio processing,
expect()is used to handle potential failures when creating a model state, running the model, or retrieving text segments. A panic in this context will terminate the worker handling the request, which may cause the entire server to shut down depending on the server configuration.
// stt/src/main.rs:11-16
lazy_static! {
static ref WHISPER: WhisperContext = WhisperContext::new_with_params(
env::var("MODEL_PATH")
.expect("MODEL_PATH is not set in env")
.as_str(),
WhisperContextParameters::default()
)
.expect("failed to load model");
}
Sources: stt/src/main.rs:11-16, 40-42, 45-48
Summary
The project's error handling is pragmatic and context-dependent. User-facing command interactions prioritize clear, immediate feedback for recoverable errors, with a generic fallback for unexpected issues. Background processing and external service integrations are designed to be resilient, logging failures and aborting the current task without crashing the bot. This layered approach ensures both a stable service for users and actionable diagnostic information for developers.