Skip to content

claude-opus-4.6 model silently falls back to default — undocumented staff flag gating #1332

@laz-jamesfuller

Description

@laz-jamesfuller

Description

When using copilot --model claude-opus-4.6 on Linux with experimental: true enabled, the CLI was falling back to a different model instead of using the requested one. The model appeared in --model allowed choices but was not listed in the /models command output initially. The subscription includes access.

This affected multiple team members across platforms (Linux and macOS). One Mac team member was affected while another was not — the difference may be related to installation method (bun vs npm).

Environment

  • Copilot CLI version: 0.0.405
  • Platform: Linux x86_64 (containerized dev environments), macOS also reported
  • Installation: bun install -g @github/copilot
  • Config: experimental: true enabled in ~/.copilot/config.json

Original Symptom

Running copilot --model claude-opus-4.6 fell back to the config default model instead of using opus-4.6. No error was shown — the fallback was silent. Only visible in the session breakdown output.

Multiple login/logout cycles (copilot /login, copilot /logout) were attempted with no effect. This was an existing Copilot CLI installation in every case — not a fresh install.

Root Cause Analysis

After decompiling the minified source (index.js), the following code paths are relevant:

1. Model selection gates opus-4.6 behind staff flag

The default model selection function gates claude-opus-4.6 exclusively behind config.staff:

// Default model selection (decompiled)
function getDefaultModel(availableModels, config) {
  if (config?.staff) {
    let model = "claude-opus-4.6";
    if (isAvailable(model, availableModels)) return model;
  }
  // Falls back to first model with cost multiplier <= 1
  return MODELS.find(m => isAvailable(m, availableModels) && getCost(m, availableModels) <= 1);
}

2. Explicit --model flag validates against API-returned model list

// Model resolution (decompiled)
async function resolveModel(cliModel, session, availableModels, logger) {
  if (cliModel) {
    if (isAvailable(cliModel, availableModels)) return cliModel;
    logger?.warning(`Model '${cliModel}' from CLI argument is not available. Falling back...`);
  }
  // Falls through to config model, env var, then default
  // ...
  let defaultModel = getDefaultModel(availableModels, config);
  return defaultModel;
}

3. Staff auto-detection checks org membership

The CLI has auto-detection that sets staff: true if the user belongs to ["microsoft", "github", "azure", "microsoftcopilot", "ms-copilot"] orgs. This auto-detection only runs if config.staff is not already defined.

4. Feature flags treat staff and experimental independently

// Feature flag resolver (decompiled)
function resolveFeatureFlags(isStaff, isExperimental) {
  switch (availability) {
    case "on":                    // Always enabled
    case "staff-or-experimental": // Either flag works
    case "staff":                 // Staff only — opus-4.6 uses THIS
    case "experimental":          // Experimental only
    case "off":                   // Always disabled
  }
}

Opus-4.6 gating uses "staff" only, not "staff-or-experimental".

Reproduction Attempts

After adding staff: true to config (which resolved the issue), we attempted to reproduce by removing it:

Test Config Command Result
1 staff: true, experimental: true --model claude-opus-4.6 ✅ opus-4.6 used
2 staff: null, experimental: true --model claude-opus-4.6 ✅ opus-4.6 used
3 no staff key, experimental: true --model claude-opus-4.6 ✅ opus-4.6 used
4 no staff, no experimental --model claude-opus-4.6 ✅ opus-4.6 used
5 no staff, no experimental no --model (config default opus-4.5) ✅ opus-4.5 used
6 no staff, no experimental, config model: opus-4.6 no --model ✅ opus-4.6 used
7 no staff, no experimental /models command ✅ opus-4.6 listed

The issue was no longer reproducible after adding then removing staff: true. This suggests either:

  1. Server-side state change: Adding staff: true may have triggered a backend state change (e.g., model entitlement cache) that persisted after removing the flag
  2. Transient API issue: The available models list returned by the API may have been temporarily missing claude-opus-4.6 for Linux clients
  3. Token refresh: The auth flow during testing may have refreshed the Copilot token, which then included updated model entitlements

Issues Found (even if not currently reproducible)

  1. Silent fallback: When --model specifies a model that fails validation, the CLI silently falls back with no user-facing warning. The logger?.warning() call exists in code but the output is not shown to the user.

  2. Undocumented staff flag: The staff config key gates access to premium model features but is not documented anywhere. Users have no way to discover this workaround.

  3. experimental insufficient: Users who enable experimental mode reasonably expect access to all available models, but opus-4.6 is gated behind staff only (not staff-or-experimental).

  4. Cross-platform: Issue observed on both Linux and macOS. macOS evidence not yet collected but at least one Mac team member also affected.

Recommendation

  • Model access should be gated purely by subscription/API entitlements, not local config flags
  • Silent fallbacks should show a clear warning to the user
  • If staff flag is intentional, it should be documented
  • Consider gating opus-4.6 as staff-or-experimental instead of staff-only

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions