Skip to content

Error Handling

GitLab MCP Server provides structured error handling that classifies errors, extracts actionable details from GitLab API responses, and suggests corrective actions to the AI assistant.

Every error from the GitLab API is classified by HTTP status code into an actionable message:

Status CodeClassificationMessage
400Bad requestCheck your input parameters
401AuthenticationGITLAB_TOKEN may be invalid or expired
403PermissionsYour token lacks the required permissions
404Not foundThe resource does not exist or you lack access
409ConflictThe resource already exists or there is a state conflict
422ValidationGitLab rejected the request due to invalid data
429Rate limitToo many requests — wait before retrying
500Server errorGitLab internal server error
502Bad gatewayGitLab is temporarily unavailable
503MaintenanceGitLab is under maintenance or overloaded

Network-level errors are also classified:

Error TypeMessage
Connection refusedGitLab server is unreachable
DNS failureGitLab server hostname could not be resolved
TimeoutRequest to GitLab timed out
TLS/SSLTLS/SSL handshake failed

The server uses five error handling helpers, chosen based on the operation type:

Read-only operations — Used for list, get, and search operations. Classifies the error and wraps it with the operation name:

list_issues: authentication failed — GITLAB_TOKEN may be invalid or expired
ScenarioFunction
Read-only operation (list, get, search)WrapErr
Mutating operation (create, update, delete)WrapErrWithMessage
Specific error with known fixWrapErrWithHint
Status-specific hint (single code)WrapErrWithStatusHint
Get operation returning 404NotFoundResult
flowchart TD
    A[Error Occurred] --> B{Operation type?}
    B -->|list / get / search| C{Is HTTP 404<br/>on GET?}
    C -->|Yes| D[NotFoundResult]
    C -->|No| E[WrapErr]
    B -->|create / update / delete| F{Known fix<br/>for this error?}
    F -->|Yes| G{Specific HTTP<br/>status code?}
    G -->|Yes| H[WrapErrWithStatusHint]
    G -->|No| I[WrapErrWithHint]
    F -->|No| J[WrapErrWithMessage]

    style D fill:#3b82f6,color:#fff
    style E fill:#6b7280,color:#fff
    style H fill:#f59e0b,color:#000
    style I fill:#f59e0b,color:#000
    style J fill:#ef4444,color:#fff

NotFoundResult — Informational 404 responses

Section titled “NotFoundResult — Informational 404 responses”

For get handlers, 404 errors are treated as informational rather than failures. Instead of returning an opaque Go error (logged at ERROR level), the handler returns a CallToolResult with IsError: true and domain-specific hints:

## ❓ Branch Not Found
Branch `feature/old` was not found in the project.
💡 **Next steps:**
- Use `gitlab_list_branches` to see available branches
- Check branch name spelling and case sensitivity

This pattern is applied to all 27 get handlers across 21 domains. It logs at INFO level (expected outcome) and provides the AI assistant with actionable next steps.

For 422 validation errors, the server automatically enriches the error with guidance based on pattern matching. Over 15 common patterns are recognized, including:

  • Missing required fields
  • Invalid date formats
  • Name/title length limits
  • Duplicate resource names
  • Invalid enum values

These hints help the AI assistant correct its request without additional API calls.

When a tool encounters an error, the response is formatted as a Markdown block with structured diagnostic fields:

## ❌ Error: list_branches
**Status**: 401 Unauthorized
**Detail**: authentication failed — GITLAB_TOKEN may be invalid or expired
**Request ID**: abc123def456
💡 **Suggestion**: Check that your token is valid and has the `api` scope.

The structured response includes:

FieldDescription
OperationThe tool action that failed
StatusHTTP status code and classification
DetailSpecific error message from GitLab
Request IDGitLab’s X-Request-Id for support tickets
SuggestionActionable hint (when available)

The server classifies errors as transient (retryable) or permanent:

TypeStatus CodesBehavior
Transient429, 5xx, timeouts, connection refusedSafe to retry after a delay
Permanent4xx (except 429)Do not retry — fix the input or configuration
❌ list_projects: authentication failed — GITLAB_TOKEN may be invalid or expired
💡 Generate a new token with api scope at GitLab → Preferences → Access Tokens
❌ create_issue: access denied — your token lacks the required permissions
Detail: 403 Forbidden
💡 Ensure the token has api scope and you have Developer+ access to the project
❌ branchProtect: conflict — Protected branch rule already exists
💡 Use gitlab_protected_branch_get to view current rules, or gitlab_protected_branch_update to modify
❌ create_issue: validation failed — title is too long (maximum is 255 characters)
💡 Shorten the title to 255 characters or less

How does the server classify GitLab API errors?

Section titled “How does the server classify GitLab API errors?”

GitLab MCP Server classifies every API error by HTTP status code into an actionable message: 401 signals an invalid or expired GITLAB_TOKEN, 403 signals missing permissions, 404 a missing resource or lack of access, 422 a validation failure, and 429 a rate limit. Network-level failures — connection refused, DNS failure, timeout, and TLS handshake errors — are classified separately. The classification drives both the wrapped error message and whether the failure is treated as retryable.

Which error wrapping function is used for which operation?

Section titled “Which error wrapping function is used for which operation?”

Read-only operations (list, get, search) use WrapErr. Mutating operations (create, update, delete) use WrapErrWithMessage, which includes the specific detail extracted from the GitLab response. When a corrective action is known, WrapErrWithHint appends a suggestion, and WrapErrWithStatusHint scopes that hint to a single HTTP status code. A get operation returning 404 uses NotFoundResult instead of returning an error.

For get handlers, 404 responses are treated as informational rather than failures. Instead of returning an opaque Go error logged at ERROR level, the handler returns a CallToolResult with IsError: true and domain-specific hints, logged at INFO level. This NotFoundResult pattern is applied to all 27 get handlers across 21 domains and gives the AI assistant actionable next steps, such as listing available resources or checking the resource name.

Should the AI assistant retry a failed operation?

Section titled “Should the AI assistant retry a failed operation?”

It depends on whether the error is transient or permanent. Transient errors — 429, 5xx, timeouts, and connection refused — are safe to retry after a delay. Permanent errors — 4xx except 429 — indicate a problem with the request itself, so retrying produces the same result. For permanent errors, fix the input parameters or configuration instead of retrying.