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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions