github/github-mcp-server · error · ErrStaleAuthorizationFlow

authorization prompt has expired

Error message

authorization prompt has expired

What it means

First guard of validateBlamePath, run by get_file_blame before any network call: strings.TrimSpace(path) == "" is rejected. The GraphQL blame query needs a concrete file path; an empty or all-whitespace path would either fail at GitHub or match nothing, so the server refuses it locally with 'path must not be empty'.

Source

Thrown at internal/oauth/manager.go:26

	"net/http"
	"os"
	"sync"
	"time"

	"golang.org/x/oauth2"
)

// DefaultAuthTimeout bounds how long a single authorization attempt waits for
// the user to complete the browser or device flow.
const DefaultAuthTimeout = 5 * time.Minute

// tokenRefreshTimeout bounds each background refresh of an expiring token so a
// stalled GitHub token endpoint cannot block a tool call indefinitely.
const tokenRefreshTimeout = 30 * time.Second

// ErrStaleAuthorizationFlow indicates that a prompt response belongs to an
// authorization flow that is no longer current.
var ErrStaleAuthorizationFlow = errors.New("authorization prompt has expired")

// flowStatus tracks the manager's single-flight authorization state.
type flowStatus int

const (
	statusIdle         flowStatus = iota // no flow running
	statusStarting                       // a flow is being prepared (brief)
	statusInProgress                     // a flow is running on a secure channel; callers may join
	statusAwaitingUser                   // a flow is running but the user must act out-of-band
)

// Outcome reports the result of an authorization attempt that did not
// immediately yield a token.
type Outcome struct {
	// UserAction, when non-nil, must be surfaced to the user. The authorization
	// flow continues in the background; the user should retry once they have
	// completed it.
	UserAction *UserAction

View on GitHub (pinned to 0ea1f775a7)

Solutions

  1. Pass a real repository-relative file path such as "src/main.go"
  2. If the path comes from a variable, default it and skip the call when blank rather than sending whitespace
  3. Trim inputs before invoking the tool to catch the mistake client-side

Example fix

// before
{"owner":"octocat","repo":"Hello-World","path":"   "}

// after
{"owner":"octocat","repo":"Hello-World","path":"README.md"}
Defensive patterns

Strategy: validation

Validate before calling

func validBlamePathPresence(p string) bool {
	return strings.TrimSpace(p) != ""
}

Type guard

func isBlamePathError(err error) bool {
	return err != nil && strings.HasPrefix(err.Error(), "path must")
}

Try / catch

if strings.TrimSpace(path) == "" {
	// skip or fetch a default file instead of calling with a blank path
	return nil, fmt.Errorf("no file path provided")
}
res, _, err := callGetFileBlame(ctx, buildArgs(owner, repo, path))
if isBlamePathError(err) {
	return nil, fmt.Errorf("fix the path argument: %w", err)
}

Prevention

When it happens

Trigger: Omitting the path argument so it defaults to ""; passing a whitespace-only string (spaces/tabs/newlines); templating bugs that interpolate an unset variable into path.

Common situations: LLM tool calls that drop a required parameter; CI scripts iterating a file list where one entry is blank; config-driven blame jobs with an empty template slot.

Related errors


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