github/github-mcp-server · error

failed to get user permission level: %w

Error message

failed to get user permission level: %w

What it means

checkPushAccess calls the REST endpoint GET /repos/{owner}/{repo}/collaborators/{username}/permission to decide push access. GitHub returns 404 when the queried user is not a collaborator at all, and 403 when the caller's token lacks the collaborators permission (typical for fine-grained PATs or app tokens without it), so lockdown checks on outside contributors or least-privilege tokens surface as this wrapped error. Only admin/write count as push access.

Source

Thrown at pkg/lockdown/lockdown.go:280

	if err := c.client.Query(ctx, &query, variables); err != nil {
		return false, "", fmt.Errorf("failed to query repository metadata: %w", err)
	}

	c.logDebug(ctx, fmt.Sprintf("queried repo access info for %s/%s: isPrivate=%t", owner, repo, bool(query.Repository.IsPrivate)))

	return bool(query.Repository.IsPrivate), string(query.Viewer.Login), nil
}

// checkPushAccess checks if the user has push access to the repository via the REST permission endpoint.
func (c *RepoAccessCache) checkPushAccess(ctx context.Context, username, owner, repo string) (bool, error) {
	if c.restClient == nil {
		return false, fmt.Errorf("nil REST client")
	}

	permLevel, _, err := c.restClient.Repositories.GetPermissionLevel(ctx, owner, repo, username)
	if err != nil {
		return false, fmt.Errorf("failed to get user permission level: %w", err)
	}

	// REST API maps "maintain" to "write" (and "triage" to "read")
	// https://docs.github.com/en/rest/collaborators/collaborators#get-repository-permissions-for-a-user
	permission := permLevel.GetPermission()
	return permission == "admin" || permission == "write", nil
}

func (c *RepoAccessCache) log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
	if c == nil || c.logger == nil {
		return
	}
	if !c.logger.Enabled(ctx, level) {
		return
	}
	c.logger.LogAttrs(ctx, level, msg, attrs...)
}

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Map a 404-wrapped failure to hasPushAccess=false instead of an error - outside users are an expected case
  2. Give the token collaborator read access: classic PAT needs repo scope; fine-grained PAT needs repository 'Collaborators: read'
  3. For GitHub Apps, request the collaborators read permission on the installation
  4. Authorize the token for SAML-protected organizations when applicable
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := cache.IsSafeContent(ctx, username, owner, repo); err != nil {
	var ghErr *github.ErrorResponse
	if errors.As(err, &ghErr) && ghErr.Response != nil && ghErr.Response.StatusCode == http.StatusNotFound {
		// user is not a collaborator: that IS the answer (no push access), not a failure
		ok, err = false, nil
	}
}

Prevention

When it happens

Trigger: Lockdown evaluating content authored by a user with no collaborator status on the repo (404); a fine-grained PAT without the repository 'Collaborators: read' permission (403); a GitHub App token missing the collaborators read permission; SAML-protected org with an unauthorized token.

Common situations: Public repos where outside contributors' content is checked; fine-grained PATs whose permission set skipped collaborator access in the name of least privilege.

Related errors


AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15). Data as JSON: /api/errors/5d781905eaa4781e. Report an issue: GitHub.