charmbracelet/crush · info

github copilot not available

Error message

github copilot not available

What it means

ErrNotAvailable signals that GitHub Copilot OAuth is not available in this build or context. loginCopilot and getCopilotToken return it as a sentinel error instead of attempting the OAuth device flow. Callers should compare with errors.Is and skip or fall back to another provider.

Source

Thrown at internal/oauth/copilot/oauth.go:25

	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/charmbracelet/crush/internal/oauth"
)

const (
	clientID = "Iv1.b507a08c87ecfe98"

	deviceCodeURL   = "https://github.com/login/device/code"
	accessTokenURL  = "https://github.com/login/oauth/access_token"
	copilotTokenURL = "https://api.github.com/copilot_internal/v2/token"
)

var ErrNotAvailable = errors.New("github copilot not available")

type DeviceCode struct {
	DeviceCode      string `json:"device_code"`
	UserCode        string `json:"user_code"`
	VerificationURI string `json:"verification_uri"`
	ExpiresIn       int    `json:"expires_in"`
	Interval        int    `json:"interval"`
}

// RequestDeviceCode initiates the device code flow with GitHub.
func RequestDeviceCode(ctx context.Context) (*DeviceCode, error) {
	data := url.Values{}
	data.Set("client_id", clientID)
	data.Set("scope", "read:user")

	req, err := http.NewRequestWithContext(ctx, "POST", deviceCodeURL, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check for the sentinel with errors.Is(err, copilot.ErrNotAvailable) and treat it as 'provider unavailable', not a hard failure.
  2. Fall back to a different provider or prompt the user to pick another auth method.
  3. Verify the build/context actually supports Copilot OAuth before calling loginCopilot.

Example fix

// before
token, err := copilot.GetToken(ctx)
if err != nil { return err }
// after
token, err := copilot.GetToken(ctx)
if errors.Is(err, copilot.ErrNotAvailable) {
    return ErrCopilotUnsupported // degrade gracefully
}
if err != nil { return err }
Defensive patterns

Strategy: fallback

Validate before calling

if copilotErr := tryCopilotLogin(); errors.Is(copilotErr, copilot.ErrNotAvailable) { /* provider disabled */ }

Type guard

func isCopilotUnavailable(err error) bool { return errors.Is(err, copilot.ErrNotAvailable) }

Try / catch

token, err := loginCopilot(ctx)
if errors.Is(err, copilot.ErrNotAvailable) {
    return fallbackProviderLogin(ctx)
}
if err != nil { return err }

Prevention

When it happens

Trigger: Calling loginCopilot or getCopilotToken when the Copilot provider is disabled/unavailable (e.g. no Copilot subscription or the feature is stubbed out in the build).

Common situations: Users select GitHub Copilot as a provider in crush but the Copilot integration is unavailable; scripts automating provider login hit this sentinel and must fall back to another auth path.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/744eeb602e686d60. Report an issue: GitHub.