# GitLab Backend Specific Flags and API Quirks in no-mistakes: glab CLI Compatibility

> Discover GitLab backend specific flags and API quirks handled by the no-mistakes tool. Learn how it ensures glab CLI compatibility with defensive programming and smart API handling.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: api-reference
- Published: 2026-07-12

---

**The `no-mistakes` tool handles multiple glab CLI versions and GitLab API edge cases through defensive flag detection, hostname-scoped authentication, and fallback pipelines in [`internal/scm/gitlab/gitlab.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/gitlab/gitlab.go).**

The `no-mistakes` repository implements a robust GitLab backend that wraps the **glab** CLI to interact with GitLab instances. Because glab evolves rapidly and GitLab's REST API has specific pagination and encoding requirements, the source code contains several specialized workarounds. These GitLab backend specific flags and API quirks ensure reliable operation across glab v1.4, v1.5x, and newer releases, regardless of whether repositories use legacy configurations or modern project paths.

## Host-Scoped Authentication and Context Isolation

To prevent stale credentials on unrelated hosts from poisoning availability checks, the implementation uses **host-scoped authentication**. When a GitLab host is explicitly configured, the code appends the `--hostname` flag to `glab auth status` commands.

In [`internal/scm/gitlab/gitlab.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/gitlab/gitlab.go) (lines 31-35), the `authArgs` builder constructs the command:

```go
// Host-scoped auth prevents cross-host credential leaks
args := []string{"auth", "status"}
if h.host != "" {
    args = append(args, "--hostname", h.host)
}

```

This ensures that `no-mistakes` validates credentials against the specific GitLab instance defined in the configuration, not the default host stored in glab's global config.

## Handling glab CLI Version Compatibility

The GitLab backend maintains compatibility across breaking changes in the glab CLI by detecting feature support at runtime rather than assuming version-specific behavior.

### The Deprecated --state opened Flag

Older glab versions required the `--state opened` flag to filter for open merge requests, while v1.5x and later removed this flag in favor of default open-only behavior. The `FindPR` implementation (lines 68-71) appends only `--output json`, relying on glab's modern defaults while avoiding errors on newer versions.

### Detecting Unsupported --mr Flags

Not every glab release supports the `glab ci status --mr` flag. The code proactively detects this limitation through stderr analysis before executing fallback logic.

The `isUnsupportedMRFlagError` function (lines 94-112) scans error output for markers like "unknown flag" or "unsupported option":

```go
func isUnsupportedMRFlagError(out []byte) bool {
    s := strings.ToLower(string(out))
    return strings.Contains(s, "unknown flag") || 
           strings.Contains(s, "unsupported option") ||
           strings.Contains(s, "invalid flag")
}

```

When detected, `GetChecks` falls back to a pipeline-job lookup via the MR view instead of the direct `--mr` flag approach.

## REST API Pagination and Path Encoding

GitLab's REST API paginates job lists with a default of 20 items per page. The implementation forces full collection through specific flag combinations and handles URL encoding quirks for project paths.

### Forcing Pagination for Pipeline Jobs

The `pipelineJobsArgs` function (lines 95-107) builds commands that use `glab api --paginate` to traverse all result pages, then merges the JSON arrays into a single response. This prevents silent data truncation when repositories have more than 20 pipeline jobs.

### Segment-by-Segment URL Encoding

The `group/project` path must be URL-escaped segment-by-segment (e.g., `group%2Fproject`) before insertion into REST endpoints. The same `pipelineJobsArgs` routine handles this by splitting on `/`, escaping each segment individually, and joining with `%2F`:

```go
func (h *Host) pipelineJobsArgs(pipelineID int) []string {
    if h.projectPath != "" {
        segments := strings.Split(h.projectPath, "/")
        for i, seg := range segments {
            segments[i] = url.PathEscape(seg)
        }
        enc := strings.Join(segments, "%2F")
        return []string{
            "api", "--paginate",
            fmt.Sprintf("projects/%s/pipelines/%d/jobs", enc, pipelineID),
        }
    }
    // Legacy fallback path...
    return []string{
        "ci", "get", "--pipeline-id", fmt.Sprintf("%d", pipelineID),
        "--output", "json", "--with-job-details",
    }
}

```

## Legacy Fallbacks and Defensive Parsing

When modern REST paths are unavailable, the code maintains compatibility through alternative command structures and robust output parsing.

### Fallback to glab ci get

When no `projectPath` is configured (legacy mode), jobs are fetched with `glab ci get --pipeline-id …`. This approach requires a current branch and cannot run from a detached-HEAD worktree. The `pipelineJobsArgs` function (lines 91-94) retains this path for backward compatibility while preferring the REST API approach when project paths are available.

### Trimming Non-JSON Banner Output

Glab occasionally prepends informational banners before JSON payloads, which breaks naive parsers. The `bytesTrimToJSON` function (lines 92-100) strips any leading non-JSON characters to ensure valid parsing:

```go
func bytesTrimToJSON(b []byte) []byte {
    // Skip banner lines until we hit JSON array/object
    for i := 0; i < len(b); i++ {
        if b[i] == '[' || b[i] == '{' {
            return b[i:]
        }
    }
    return b
}

```

## Summary

- **Host-scoped authentication** prevents credential cross-contamination by appending `--hostname` to auth commands in [`internal/scm/gitlab/gitlab.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/gitlab/gitlab.go).
- **Version compatibility** is maintained through runtime detection of deprecated flags like `--state opened` and unsupported flags like `--mr`.
- **Defensive error handling** via `isUnsupportedMRFlagError` enables graceful fallbacks when glab versions lack specific features.
- **Forced pagination** using `--paginate` ensures complete job lists when querying GitLab's REST API for pipeline status.
- **Segment-by-segment URL encoding** correctly handles project paths containing slashes by encoding each part separately before joining with `%2F`.
- **Legacy support** retains `glab ci get` fallback for configurations lacking explicit project paths, despite detached-HEAD limitations.

## Frequently Asked Questions

### What triggers the fallback from --mr to legacy pipeline lookups?

The fallback triggers when `isUnsupportedMRFlagError` detects "unknown flag" or "unsupported option" messages in glab's stderr output. This occurs on glab versions older than v1.5 that do not recognize the `--mr` flag in `glab ci status` commands.

### How does no-mistakes handle GitLab API pagination?

When a `projectPath` is configured, the `pipelineJobsArgs` function builds a command using `glab api --paginate` to automatically traverse all result pages. The implementation then merges the paginated JSON arrays into a single response to prevent the default 20-item limit from truncating job lists.

### Why is URL encoding necessary for project paths?

GitLab's REST API requires the `group/project` path to appear URL-encoded in the endpoint URL. The code splits the path on `/`, escapes each segment individually using `url.PathEscape`, and rejoins them with `%2F` to ensure proper handling of special characters while maintaining the API's expected format.

### Which glab versions are compatible with no-mistakes?

The code supports glab v1.4 through v1.5x and later by using defensive programming techniques. It detects unsupported flags at runtime, removes deprecated flags like `--state opened` for newer versions, and provides legacy fallbacks for older CLI versions that cannot use modern REST API endpoints.