Skip to content

[BUG] Studio Models panel silently no-ops when agent model is a function returning a fallback array #27088

Description

@mikhael28

Describe the Bug

Studio's Models panel (shown in the agent Config side panel when an agent is configured with a fallback array) lets you reorder entries, change the provider/model of an entry, and enable/disable entries. All of this works when model is a static array, but when model is a function that returns an array every action is a silent no-op.

Agent.getModelList() resolves the function and returns the list, so the server includes modelList in GET /api/agents/:agentId and Studio renders the panel. But Agent.reorderModels() and Agent.updateModelInModelList() (packages/core/src/agent/agent.ts) start with if (!Array.isArray(this.model)), log Model is not an array, and return. The server handlers for POST /agents/:agentId/models/reorder and POST /agents/:agentId/models/:modelConfigId still respond 200 { message: 'Model list reordered' } / { message: 'Model updated in model list' }, so the UI shows success and nothing changed.

A function-valued model array is the documented way to build the chain from runtime values (environment variables, request context, provider keys), so this is a common configuration for deployed agents.

Related gaps in the same panel, worth fixing alongside:

  • There is no control for a per-entry maxRetries, even though the server route accepts it and the response includes it.
  • AgentMetadataModelList (packages/playground/src/domains/agents/components/agent-metadata/agent-metadata-model-list.tsx) seeds its list and per-item enabled state once with useState(() => modelList), so a refetch of the agent does not update what the panel shows.
  • The panel is not documented. Model fallbacks are only described at the code level in docs/src/content/en/models/index.mdx; nothing under docs/studio mentions the panel, reordering, or enable/disable.

Note: changes made in this panel are intentionally in-memory only today and revert on restart. Making them persistent is tracked separately as a stacked feature request (linked below once filed). This issue is only about the panel working as designed.

Steps To Reproduce

  1. Configure an agent with a function returning a fallback array:
import { Agent } from '@mastra/core/agent';
import type { ModelWithRetries } from '@mastra/core/agent';

function buildChain(): ModelWithRetries[] {
  return [
    { id: 'primary', model: process.env.PRIMARY_MODEL ?? 'anthropic/claude-sonnet-4-5', maxRetries: 2 },
    { id: 'fallback', model: 'anthropic/claude-haiku-4-5', maxRetries: 1 },
  ];
}

export const agent = new Agent({
  id: 'fallback-agent',
  name: 'Fallback Agent',
  instructions: 'You are a helpful assistant.',
  model: () => buildChain(),
});
  1. Run mastra dev, open the agent in Studio, open the Config side panel. The Models section appears with both entries.
  2. Drag fallback above primary, or toggle fallback off, or change its model.
  3. Observe the request returns 200 and the server logs Model is not an array. Refresh the page: the list is unchanged.
  4. Replace model: () => buildChain() with model: buildChain() and repeat. Now the actions take effect (until restart).

Link to Minimal Reproducible Example

Snippet above; happy to turn it into a repo if needed.

Expected Behavior

Either:

  • Reorder / update / enable-disable work for function-valued model arrays the same way they do for static arrays (for example by resolving the function once and replacing this.model with the mutated resolved array, the same way __updateModel replaces the whole value), or
  • the server returns an error and Studio renders the panel read-only (or hides the mutators) when the model is dynamic, instead of reporting success.

Plus: a maxRetries control in the panel, panel state that follows refetches, and a short docs section under docs/studio describing the Models panel and that its changes are in-memory only.

Environment Information

  • @mastra/core 1.78.0-alpha.2 (main at d99fa30), also reproduces on recent stable releases
  • Node 22, macOS
  • Studio via mastra dev

Verification

  • I have searched the existing issues to make sure this is not a duplicate
  • I have included sufficient information for the team to reproduce and understand the issue

Activity

  1. added
    bugSomething isn't working
    UI / StudioIssues with the Mastra Studio
    AgentsIssues regarding Mastra's Agent primitive
    @mastra/coreIssues whose primary fix belongs in @mastra/core
    on Oct 14, 2026
  2. dane-ai-mastra commented on Oct 14, 2026

    @dane-ai-mastra
    Contributor

    Thank you for opening this issue. It is waiting for maintainer triage or approval.

    Please wait until maintainers remove the triage or approval label before opening a pull request.

  3. mikhael28 commented on Oct 14, 2026

    @mikhael28
    ContributorAuthor

    Stacked follow-up: #27089 (persist model fallback chain edits made in Studio) builds on this fix.

  4. mastra-platform commented on Oct 14, 2026

    @mastra-platform
    Contributor
    Type bug — Studio Models panel mutations are silently dropped when model is a function returning an array
    Route Plan fix
    Severity 🟡 medium — Studio edits report success but nothing changes; only affects function-valued fallback models
    Confidence high — exact code path checked on current main (04b4775)
    Effort low — two core methods, two server handlers, and tests
    Impact medium — fallback editing in Studio is broken for agents with dynamic models; workaround is to use a static array
    Next step Plan fix: resolve a function-valued model in reorderModels / updateModelInModelList

    Understanding

    • GET /api/agents/:agentId calls agent.getModelList(). That method resolves a function-valued model (packages/core/src/agent/agent.ts ~3836), so the panel renders.
    • POST .../models/reorder and POST .../models/:modelConfigId (packages/server/src/server/handlers/agents.ts ~3589–3660) first check getModelList(), which passes. They then call the sync methods reorderModels / updateModelInModelList. Both return early when !Array.isArray(this.model) (agent.ts:3950–3952, :3968–3980) and only log Model is not an array. The route still returns 200.
    • The UI makes this harder to notice: agent-metadata-model-list.tsx seeds useState once and updates optimistically, so the panel looks updated until you reload.

    Fix direction: make both methods async. Resolve the function once (the same way resolveModelSelection / normalizeModelFallbacks do), replace this.model with the resolved array, then apply the change. await the methods in the handlers. Return a non-2xx status if the change can't be applied. Add a function-valued case to packages/core/src/agent/__tests__/model-list.test.ts.

    Related: #27089 (persistence, a separate follow-up), #13410 / #13445 (reorder sorting), #9481 (model reset). No open or merged PR fixes this yet.

    Assumptions

    • Resolving the function once and storing the result as a static array is acceptable for Studio edits. This matches how in-memory edits to a static array already behave. Resolution uses an empty/default requestContext.
    • The maxRetries control, refetch syncing, and Studio docs the reporter asked for are follow-ups, not required for this fix.
    • Persistence is out of scope ([FEATURE] Persist agent model fallback chain edits made in Studio (Editor-owned model list) #27089).
    • This refresh was triggered by the previous Factory handoff comment. There is no new information from the reporter and the code is unchanged on main, so the verdict is unchanged.

    Open questions

    • If the function's output depends on requestContext, is it acceptable to store one resolved result? Or should Studio edits on dynamic models be rejected with an explicit error and the panel shown read-only?

    Reproduction

    Not run live. Static trace on current source. A deterministic repro: new Agent({ model: () => [{ model: a }, { model: b }] }) → await getModelList() returns 2 entries → reorderModels([...ids].reverse()) logs Model is not an array and the list is unchanged.

  5. self-assigned this
    on Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

@mastra/coreIssues whose primary fix belongs in @mastra/coreAgentsIssues regarding Mastra's Agent primitiveUI / StudioIssues with the Mastra StudiobugSomething isn't workingcustomer-engeffort:lowimpact:mediumstatus: auto-triagedIssue entered the automatic triage queue

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions