kanboard-api/errors.go
Oliver Jakoubek 449cd2626c feat: add OperationFailedError with actionable hints
The Kanboard API returns only true/false for many operations without
explaining why they failed. Added OperationFailedError type that
includes operation details and hints about possible causes.

Updated MoveTaskPosition and MoveTaskToProject to use this new error
type, providing users with actionable debugging information instead
of generic "failed to move task" messages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 11:12:25 +01:00

130 lines
3.9 KiB
Go

package kanboard
import (
"errors"
"fmt"
)
// Network errors
var (
// ErrConnectionFailed indicates a connection to the Kanboard server failed.
ErrConnectionFailed = errors.New("connection to Kanboard server failed")
// ErrTimeout indicates a request timed out.
ErrTimeout = errors.New("request timed out")
// ErrTooManyRedirects indicates the server returned too many redirects.
ErrTooManyRedirects = errors.New("too many redirects")
)
// Authentication errors
var (
// ErrUnauthorized indicates authentication failed.
ErrUnauthorized = errors.New("authentication failed: invalid credentials")
// ErrForbidden indicates insufficient permissions.
ErrForbidden = errors.New("access forbidden: insufficient permissions")
)
// Resource errors
var (
// ErrNotFound indicates a resource was not found.
ErrNotFound = errors.New("resource not found")
// ErrProjectNotFound indicates the specified project was not found.
ErrProjectNotFound = errors.New("project not found")
// ErrTaskNotFound indicates the specified task was not found.
ErrTaskNotFound = errors.New("task not found")
// ErrColumnNotFound indicates the specified column was not found.
ErrColumnNotFound = errors.New("column not found")
// ErrCommentNotFound indicates the specified comment was not found.
ErrCommentNotFound = errors.New("comment not found")
// ErrCategoryNotFound indicates the specified category was not found.
ErrCategoryNotFound = errors.New("category not found")
)
// Logic errors
var (
// ErrAlreadyInLastColumn indicates a task is already in the last column.
ErrAlreadyInLastColumn = errors.New("task is already in the last column")
// ErrAlreadyInFirstColumn indicates a task is already in the first column.
ErrAlreadyInFirstColumn = errors.New("task is already in the first column")
// ErrTaskClosed indicates a task is already closed.
ErrTaskClosed = errors.New("task is already closed")
// ErrTaskOpen indicates a task is already open.
ErrTaskOpen = errors.New("task is already open")
)
// Validation errors
var (
// ErrEmptyTitle indicates a task title cannot be empty.
ErrEmptyTitle = errors.New("task title cannot be empty")
// ErrInvalidProjectID indicates an invalid project ID was provided.
ErrInvalidProjectID = errors.New("invalid project ID")
)
// APIError represents an error returned by the Kanboard API.
type APIError struct {
Code int
Message string
}
// Error implements the error interface.
func (e *APIError) Error() string {
return fmt.Sprintf("Kanboard API error (code %d): %s", e.Code, e.Message)
}
// OperationFailedError represents an API operation that returned false without details.
// The Kanboard API often returns only true/false without explaining why an operation failed.
type OperationFailedError struct {
Operation string
Hints []string
}
// Error implements the error interface.
func (e *OperationFailedError) Error() string {
msg := fmt.Sprintf("%s: operation failed", e.Operation)
if len(e.Hints) > 0 {
msg += " (possible causes: " + e.Hints[0]
for _, hint := range e.Hints[1:] {
msg += ", " + hint
}
msg += ")"
}
return msg
}
// IsNotFound returns true if the error indicates a resource was not found.
func IsNotFound(err error) bool {
return errors.Is(err, ErrNotFound) ||
errors.Is(err, ErrProjectNotFound) ||
errors.Is(err, ErrTaskNotFound) ||
errors.Is(err, ErrColumnNotFound) ||
errors.Is(err, ErrCommentNotFound) ||
errors.Is(err, ErrCategoryNotFound)
}
// IsUnauthorized returns true if the error indicates an authentication failure.
func IsUnauthorized(err error) bool {
return errors.Is(err, ErrUnauthorized)
}
// IsAPIError returns true if the error is an APIError from the Kanboard API.
func IsAPIError(err error) bool {
var apiErr *APIError
return errors.As(err, &apiErr)
}
// IsOperationFailed returns true if the error is an OperationFailedError.
func IsOperationFailed(err error) bool {
var opErr *OperationFailedError
return errors.As(err, &opErr)
}