Error Handling
Relevant source files
The following files were used as context for generating this wiki page:The dokku-mcp project employs a layered approach to error handling, ensuring that errors are managed appropriately at different levels of the architecture, from low-level command execution to high-level business logic. The system distinguishes between infrastructure errors (e.g., SSH command failures), domain-specific errors (e.g., an application already exists), and validation issues.
The primary goal is to provide clear, actionable feedback to the MCP client (and by extension, the LLM) while maintaining system security and stability. This is achieved through custom error types, security validation at the command execution layer, and specific handling logic within each plugin. The project standardizes on using fmt.Errorf with the %w verb to wrap errors, preserving the error chain for debugging purposes.
Sources: CONTRIBUTING.md:73-73, internal/dokku-api/client.go, internal/server-plugins/app/plugin.go
Core Error Types
The system defines several custom error types and sentinel errors to represent specific failure conditions across different architectural layers.
dokku-api Infrastructure Errors
At the lowest level, the dokku-api package defines errors related to command execution and resource state within Dokku itself.
NotFoundError
The NotFoundError is a specialized error used to indicate that a Dokku resource (typically an application) does not exist. It wraps the standard ErrAppNotFound sentinel error, adding context about the command that was executed.
This diagram shows the structure of the NotFoundError type.
Sources: internal/dokku-api/errors.go:10-20
ErrAppNotFound: A sentinel errorerrors.New("app not found")that provides a standard base for not-found conditions.NotFoundErrorstruct: Wraps the underlying error with theCommandthat failed.IsNotFoundError(): A helper function to check if an error in a chain is aNotFoundErrororErrAppNotFound.
Sources: internal/dokku-api/errors.go:6-29
Application Domain Errors
The application domain defines its own set of sentinel errors to represent failures in business logic, independent of the underlying infrastructure. These are used by use cases and repositories to signal specific outcomes.
| Error | Description |
|---|---|
ErrApplicationNotFound | The requested application does not exist in the system. |
ErrApplicationAlreadyExists | An attempt was made to create an application that already exists. |
ErrInvalidApplicationName | The provided application name is invalid. |
ErrDeploymentInProgress | A deployment is already active for the application. |
ErrApplicationNotDeployed | The operation requires a deployed application, but it is not. |
Sources: internal/server-plugins/app/plugin.go:252-255, 276-279, 297-300, 321-327
Validation Errors and Warnings
The ValidationService provides a structured way to report issues with input data without immediately halting an operation. It distinguishes between fatal errors and informational warnings.
This diagram illustrates the relationship between ValidationResult, ValidationError, and ValidationWarning.
Sources: internal/server-plugins/app/domain/application-validation.service.go:16-33
ValidationResult: A container for the outcome of a validation check.IsValidisfalseonly if there areValidationErrors.ValidationError: Represents a condition that makes the input invalid (e.g., negative scale value, invalid name format). Each error has aCodelikeINVALID_SCALE.ValidationWarning: Represents a condition that is valid but not recommended (e.g., high scale value, using a buildpack that requires auto-detection). Each warning has aCodelikeHIGH_SCALE_WARNINGorAUTO_BUILDPACK.
Sources: internal/server-plugins/app/domain/application-validation.service.go:100-106, 122-128
Error Handling in the Dokku API Client
The dokku-api client is a critical point for error handling, as it is the primary interface to the external Dokku CLI. It incorporates robust security checks and intelligent error parsing.
Sources: internal/dokku-api/client.go
Command Validation and Security
Before any command is executed over SSH, it undergoes a strict validation process within the ValidateCommand function. This is a security-critical step to prevent command injection.
This flowchart shows the security validation steps for a Dokku command before execution.
Sources: internal/dokku-api/client.go:15-51, internal/dokku-api/client_blacklist_test.go
The validation checks include:
- Blacklist Check: The command is checked against a list of blacklisted patterns (e.g., "destroy", "uninstall"). This list can be configured at runtime via
SetBlacklist. - Dangerous Character Check: Both the command name and its arguments are scanned for characters that could be used for command injection, such as
;,&,|,\``, and$`. - Invalid Character Check: The command name is further restricted to alphanumeric characters, dashes (
-), and colons (:).
Sources: internal/dokku-api/client.go:20-44, [internal/dokku-api/client_blacklist_test.go:27-46]
SSH Command Execution Errors
After a command is executed, the handleCommandError function in the client intelligently processes the result. It avoids treating all non-zero exit codes as generic failures.
This sequence diagram shows the error handling flow within the Dokku API client upon a failed SSH command.
Sources: internal/dokku-api/client.go:163-182, 214-221
Key behaviors in handleCommandError:
- App Not Found Wrapping: If a command is app-scoped (e.g.,
apps:report) and the Dokku output contains "does not exist" or "has not been deployed", the genericexec.ExitErroris wrapped in the specificdokkuApi.NotFoundError. This allows upstream callers to handle "not found" cases gracefully. - Empty Logs Handling: If a
logscommand fails because the app has not been deployed, it is not treated as an error. Instead, an empty byte slice is returned, simplifying logic in the calling code. - JSON Probe Failures: When the client probes for JSON support (
--format json), certain errors like "unknown flag" are recognized as a clear signal that JSON is not supported, preventing a generic failure.
Sources: internal/dokku-api/client.go:163-221, [internal/server-plugins/app/infrastructure/application_repository.go:80-84]
Error Propagation and Presentation
Errors from lower layers are caught and translated into meaningful responses at the higher layers of the application.
Plugin Tool Handlers
Within each server plugin, the tool handlers are responsible for catching domain and infrastructure errors and converting them into user-friendly mcp.CallToolResult messages. This ensures the LLM receives a clear explanation of what went wrong.
// Source: internal/server-plugins/app/plugin.go:248-262
func (p *AppsServerPlugin) handleCreateApp(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// ...
cmd := appusecases.CreateApplicationCommand{Name: name}
if err := p.applicationUseCase.CreateApplication(ctx, cmd); err != nil {
if errors.Is(err, appdomain.ErrApplicationAlreadyExists) {
return mcp.NewToolResultError(fmt.Sprintf("Application '%s' already exists", name)), nil
}
if errors.Is(err, appdomain.ErrInvalidApplicationName) {
return mcp.NewToolResultError(fmt.Sprintf("Invalid application name '%s'", name)), nil
}
return mcp.NewToolResultError(fmt.Sprintf("Failed to create application: %v", err)), nil
}
return mcp.NewToolResultText(fmt.Sprintf("Application '%s' created successfully", name)), nil
}
In this example from the app plugin, specific domain errors like ErrApplicationAlreadyExists are checked using errors.Is, and a tailored error message is returned to the client. Generic errors are also caught and formatted for presentation.
Sources: [internal/server-plugins/app/plugin.go:252-258]
Contribution Guidelines
The project's contribution guidelines explicitly state the expected practices for error handling, ensuring consistency across the codebase.
- Code Review Checklist: Reviewers must verify that there is "proper error handling for all new paths".
- Error Wrapping: The official style is to "Use
fmt.Errorfwith%wto wrap errors with context."
These guidelines reinforce the architectural principles of maintaining a clear error chain and providing context at each layer.
Sources: CONTRIBUTING.md:69-73