google-gemini/gemini-cli · critical · Error
Model policy chain must only have one `isLastResort`.
Error message
Model policy chain must only have one `isLastResort`.
What it means
Thrown by validateModelPolicyChain() when more than one entry in the chain has isLastResort set to true. The system expects exactly one terminal fallback so that recovery logic is deterministic; multiple last-resort models create ambiguity about which to use when all primary models fail. This is a structural invariant of the policy chain.
Source
Thrown at packages/core/src/availability/policyCatalog.ts:161
* Provides a default policy scaffold for models not present in the catalog.
*/
export function createDefaultPolicy(
model: string,
options?: { isLastResort?: boolean },
): ModelPolicy {
return definePolicy({ model, isLastResort: options?.isLastResort });
}
export function validateModelPolicyChain(chain: ModelPolicyChain): void {
if (chain.length === 0) {
throw new Error('Model policy chain must include at least one model.');
}
const lastResortCount = chain.filter((policy) => policy.isLastResort).length;
if (lastResortCount === 0) {
throw new Error('Model policy chain must include an `isLastResort` model.');
}
if (lastResortCount > 1) {
throw new Error('Model policy chain must only have one `isLastResort`.');
}
}
/**
* Helper to define a ModelPolicy with default actions and state transitions.
* Ensures every policy is a fresh instance to avoid shared state.
*/
function definePolicy(config: PolicyConfig): ModelPolicy {
return {
model: config.model,
isLastResort: config.isLastResort,
maxAttempts: config.maxAttempts,
actions: { ...DEFAULT_ACTIONS, ...(config.actions ?? {}) },
stateTransitions: {
...DEFAULT_STATE,
...(config.stateTransitions ?? {}),
},
};View on GitHub (pinned to 5024443c72)
Solutions
- Ensure exactly one entry has isLastResort: true; clear the flag on all others.
- When merging chains, strip isLastResort from the first chain before appending a chain that already has one.
- Use createDefaultPolicy(model) (without isLastResort) for primary models and reserve the flag for the single fallback.
- After building programmatically, run: const lr = chain.filter(p => p.isLastResort); if (lr.length > 1) lr.slice(1).forEach(p => p.isLastResort = false).
Example fix
// before — two last-resort entries
const chain = [
definePolicy({ model: 'gemini-pro', isLastResort: true }),
definePolicy({ model: 'gemini-flash', isLastResort: true }),
];
validateModelPolicyChain(chain); // throws
// after — only the true fallback is marked
const chain = [
definePolicy({ model: 'gemini-pro' }),
definePolicy({ model: 'gemini-flash', isLastResort: true }),
]; Defensive patterns
Strategy: validation
Validate before calling
// Ensure exactly one last-resort entry
const lastResortIndices = chain
.map((p, i) => (p.isLastResort ? i : -1))
.filter((i) => i >= 0);
if (lastResortIndices.length > 1) {
// Keep only the first, clear the rest
for (let i = 1; i < lastResortIndices.length; i++) {
chain[lastResortIndices[i]].isLastResort = false;
}
}
validateModelPolicyChain(chain); Type guard
function chainHasSingleLastResort(chain: ModelPolicyChain): boolean {
return chain.filter((p) => p.isLastResort).length === 1;
} Try / catch
try {
validateModelPolicyChain(chain);
} catch (e) {
if (e instanceof Error && e.message.includes('only have one')) {
// Deduplicate: keep the last last-resort entry, clear others
const lrs = chain.filter((p) => p.isLastResort);
lrs.slice(0, -1).forEach((p) => (p.isLastResort = false));
validateModelPolicyChain(chain);
} else throw e;
} Prevention
- When merging chains, strip isLastResort from all but one.
- Use a helper function that enforces the single-last-resort invariant on construction.
- Add a unit test asserting validateModelPolicyChain passes for all shipped chains.
- Avoid marking primary models as isLastResort defensively.
When it happens
Trigger: Calling validateModelPolicyChain(chain) where two or more entries have isLastResort: true. For example, [{ model: 'a', isLastResort: true }, { model: 'b', isLastResort: true }].
Common situations: Concatenating two chains (e.g., custom + default) where both already contain a last-resort entry; marking every model as isLastResort defensively; merging chains from multiple config sources without deduplication; copying a policy object and accidentally duplicating the flag.
Related errors
- Model policy chain must include an `isLastResort` model.
- Model policy chain must include at least one model.
- ${originalMessage}. The initial COMPUTE_ADC attempt also fai
- Invalid taskId: ${taskId}
- Security violation: Null byte detected in path.
AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12).
Data as JSON: /api/errors/90715d9797b52145.
Report an issue: GitHub.