April 15, 2026 โ€ข Version: v2026.4.14-beta.1

Dashboard Model Dropdown Displays Models from Unconfigured Providers

The Agent model selection dropdown in the OpenClaw Dashboard shows all supported models regardless of provider configuration status, causing user confusion when selecting unavailable models.

๐Ÿ” Symptoms

User-Reported Behavior

When accessing the Dashboard at http://localhost:8080 and navigating to Agent Settings, the Primary Model dropdown displays an extensive list of models:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Primary Model                                    โ–ผ     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๐Ÿ” Search models...                                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  โ–ผ Alibaba Cloud (bailian)                              โ”‚
โ”‚      bailian/kimi-k2.5                                  โ”‚
โ”‚      bailian/qwen-plus                                  โ”‚
โ”‚  โ–ผ Anthropic                                            โ”‚
โ”‚      anthropic/claude-opus-4-5                         โ”‚
โ”‚      anthropic/claude-sonnet-4                          โ”‚
โ”‚  โ–ผ Amazon Bedrock                                       โ”‚
โ”‚      bedrock/anthropic.claude-3-5-sonnet               โ”‚
โ”‚      bedrock/anthropic.claude-3-opus                    โ”‚
โ”‚  โ–ผ OpenAI                                               โ”‚
โ”‚      openai/gpt-4o                                       โ”‚
โ”‚      openai/gpt-4-turbo                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Failure Scenario

When a user selects a model from an unconfigured provider (e.g., anthropic/claude-opus-4-5) and attempts to save or use the agent:

$ openclaw agent update --model anthropic/claude-opus-4-5
[ERROR] Provider 'anthropic' is not configured. 
        Please configure credentials in config.yaml or set environment variables.
        Run 'openclaw config list' to see current provider status.

Technical Manifestation

In the browser console, the dropdown component renders models from src/models/supported-models.json without checking provider availability:

[OpenClaw] Model list loaded: 127 models
[OpenClaw] Provider check skipped for dropdown population

๐Ÿง  Root Cause

Architectural Issue

The Dashboard’s model selector component (src/components/ModelSelector.tsx) loads the complete list of supported models from the static models registry during component initialization:

// src/components/ModelSelector.tsx - Line 23-45
function ModelSelector() {
  const [models, setModels] = useState<Model[]>([]);
  
  useEffect(() => {
    // Current implementation - loads ALL models
    const allModels = getSupportedModels();
    setModels(allModels);
  }, []);
  
  // ... rest of component
}

Missing Provider Availability Check

The component does not call getConfiguredProviders() or equivalent to filter models by provider availability. The models registry and provider configuration exist in separate data domains with no integration:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Models Registry                โ”‚
โ”‚  (src/models/supported-models.ts)โ”‚
โ”‚                                 โ”‚
โ”‚  โ€ข 127 models defined           โ”‚
โ”‚  โ€ข Grouped by provider          โ”‚
โ”‚  โ€ข No runtime validation        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚
                โ–ผ NO INTEGRATION
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Provider Configuration         โ”‚
โ”‚  (config.yaml / env vars)       โ”‚
โ”‚                                 โ”‚
โ”‚  โ€ข User-configured credentials  โ”‚
โ”‚  โ€ข Provider availability state  โ”‚
โ”‚  โ€ข NOT consulted by UI          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Flow Gap

  1. User opens Dashboard โ†’ ModelSelector component mounts
  2. Component fetches all models โ†’ getSupportedModels() returns complete static list
  3. No API call to backend โ†’ Component does not query /api/providers/status
  4. Dropdown renders all models โ†’ Including those from unconfigured providers
  5. User selects invalid model โ†’ Runtime error occurs only at execution time

Affected Code Path

src/
โ”œโ”€โ”€ components/
โ”‚   โ””โ”€โ”€ ModelSelector.tsx        โ† Does not filter by provider config
โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ providerService.ts       โ† Contains getConfiguredProviders() but unused
โ””โ”€โ”€ models/
    โ””โ”€โ”€ supported-models.ts      โ† Returns unfiltered model list

๐Ÿ› ๏ธ Step-by-Step Fix

Modify src/components/ModelSelector.tsx to filter models based on provider availability:

// src/components/ModelSelector.tsx - FIXED IMPLEMENTATION
import { useState, useEffect } from 'react';
import { getSupportedModels, Model } from '../models/supported-models';
import { getConfiguredProviders } from '../services/providerService';

function ModelSelector({ onModelSelect }: Props) {
  const [models, setModels] = useState<Model[]>([]);
  const [configuredProviders, setConfiguredProviders] = useState<Set<string>>(new Set());
  const [showOnlyConfigured, setShowOnlyConfigured] = useState(true);
  
  useEffect(() => {
    async function loadData() {
      // Step 1: Get list of configured providers
      const providers = await getConfiguredProviders();
      const configuredSet = new Set(providers.map(p => p.id));
      setConfiguredProviders(configuredSet);
      
      // Step 2: Load all models
      const allModels = getSupportedModels();
      
      // Step 3: Filter to only configured providers
      const filteredModels = showOnlyConfigured
        ? allModels.filter(model => configuredSet.has(model.provider))
        : allModels;
      
      setModels(filteredModels);
    }
    
    loadData();
  }, [showOnlyConfigured]);
  
  // ... rest of component
}

Option B: Add Visual Indicator for Unconfigured Models

If maintaining visibility of all models with visual distinction:

// src/components/ModelSelector.tsx - ALTERNATIVE FIX
function ModelSelector({ onModelSelect }: Props) {
  const [models, setModels] = useState<Model[]>([]);
  const [configuredProviders, setConfiguredProviders] = useState<Set<string>>(new Set());
  
  useEffect(() => {
    async function loadData() {
      const providers = await getConfiguredProviders();
      setConfiguredProviders(new Set(providers.map(p => p.id)));
      setModels(getSupportedModels());
    }
    loadData();
  }, []);
  
  const isProviderConfigured = (providerId: string) => {
    return configuredProviders.has(providerId);
  };
  
  return (
    <select onChange={(e) => onModelSelect(e.target.value)}>
      {models.map(model => (
        <option 
          key={model.id}
          value={model.id}
          disabled={!isProviderConfigured(model.provider)}
          style={{
            color: isProviderConfigured(model.provider) ? 'inherit' : '#999',
            backgroundColor: isProviderConfigured(model.provider) ? 'white' : '#f5f5f5'
          }}
        >
          {model.displayName}
          {!isProviderConfigured(model.provider) && ' โš ๏ธ (provider not configured)'}
        </option>
      ))}
    </select>
  );
}

Option C: Backend-Driven Filtering

Add a new API endpoint that returns only available models:

// src/routes/api/models/available.ts
import { Router } from 'express';
import { getSupportedModels } from '../../models/supported-models';
import { getConfiguredProviders } from '../../services/providerService';

const router = Router();

router.get('/available', async (req, res) => {
  const configuredProviders = await getConfiguredProviders();
  const providerIds = new Set(configuredProviders.map(p => p.id));
  
  const availableModels = getSupportedModels()
    .filter(model => providerIds.has(model.provider));
  
  res.json({
    models: availableModels,
    configuredProviders: configuredProviders.map(p => p.id)
  });
});

export default router;

๐Ÿงช Verification

Verification Steps

After applying the fix, verify the behavior through these methods:

1. Dashboard UI Verification

# Start the Dashboard
$ openclaw dashboard start

# Open browser to http://localhost:8080
# Navigate to Agent Settings โ†’ Primary Model dropdown
# 
# Expected: Only models from configured providers appear
# Example: If only bailian is configured, only bailian/* models show

2. API Endpoint Verification

# If using Option C (backend filtering)
$ curl http://localhost:8080/api/models/available | jq

# Expected output:
{
  "models": [
    {"id": "bailian/kimi-k2.5", "provider": "bailian", ...},
    {"id": "bailian/qwen-plus", "provider": "bailian", ...}
  ],
  "configuredProviders": ["bailian"]
}

# Should NOT contain anthropic, bedrock, openai models

3. Component Unit Test

# Run the ModelSelector component tests
$ npm test -- --grep "ModelSelector"

# Expected: Test passes verifying filtering logic
โœ“ filters models by configured provider
โœ“ shows visual indicator for unconfigured models
โœ“ updates when provider configuration changes

4. Integration Test

# Configure a new provider and verify dropdown updates
$ openclaw config add-provider anthropic --api-key sk-ant-...

# Refresh Dashboard
# Verify anthropic models now appear in dropdown

Exit Code Verification

# Verify no console errors in Dashboard
$ openclaw dashboard start --debug 2>&1 | grep -i "model\|provider"

[DEBUG] Loading configured providers: ["bailian"]
[DEBUG] Filtering 127 models to 2 available (bailian)
[DEBUG] ModelSelector rendered with 2 options

โš ๏ธ Common Pitfalls

Edge Cases to Handle

  • No providers configured: Dropdown should display empty state with message "Configure a provider to see available models"
  • Provider configured mid-session: ModelSelector should re-fetch provider list when receiving focus or on window focus event
  • Provider API key becomes invalid: Models remain visible (server-side validation handles runtime errors)
  • Race condition on initial load: Show loading skeleton while fetching provider configuration

Environment-Specific Considerations

Docker Deployment

# When running in Docker, provider config is read from:
# 1. Environment variables (PRIORITY)
# 2. Mounted config.yaml at /app/config.yaml

# Verify config is mounted correctly:
$ docker exec <container-id> cat /app/config.yaml | grep -A5 providers

# Expected: Shows configured providers

macOS Installation

# Config location: ~/.openclaw/config.yaml
# Verify file permissions:
$ ls -la ~/.openclaw/config.yaml
-rw-r--r--  openclaw ~/.openclaw/config.yaml

# If permission denied, fix with:
$ chmod 644 ~/.openclaw/config.yaml

Windows (WSL2)

# Config location: ~/.openclaw/config.yaml (WSL2 path)
# Or: C:\Users\<username>\.openclaw\config.yaml

# Ensure line endings are LF, not CRLF:
$ dos2unix ~/.openclaw/config.yaml 2>/dev/null || sed -i 's/\r$//' ~/.openclaw/config.yaml

Configuration Mistakes

Incorrect provider ID in config:
# WRONG - provider ID mismatch
providers:
  anthropic_api:
    type: anthropic    # Should match model provider name

CORRECT

providers: anthropic: type: anthropic

Missing required fields:
# WRONG - missing api_key
providers:
  anthropic:
    type: anthropic
    # api_key is required

CORRECT

providers: anthropic: type: anthropic api_key: sk-ant-…

Connected Issues

  • ERR_PROVIDER_NOT_CONFIGURED: Occurs when attempting to use a model from an unconfigured provider. Currently happens at runtime rather than UI level.
  • ERR_API_KEY_INVALID: Provider is configured but credentials are invalid. Related to the dropdown showing models that pass config check but fail auth.
  • ERR_MODEL_NOT_FOUND: Model ID format changed but Dashboard model list is stale. May occur after OpenClaw version upgrade.

Historical Context

VersionIssueResolution
v2026.3.xProvider dropdown shows all providers regardless of configPartial fix - provider list filtered, model list not
v2026.2.xAPI credentials stored in plain text in config.yamlAdded encryption support
v2026.1.xModel selector unresponsive on large model listsVirtual scrolling added

Debugging Commands

# List configured providers
$ openclaw config list --providers

# Test specific provider connectivity
$ openclaw provider test anthropic --model claude-3-5-sonnet

# View supported models for a provider
$ openclaw models list --provider anthropic

# Validate config.yaml
$ openclaw config validate

Evidence & Sources

This troubleshooting guide was automatically synthesized by the FixClaw Intelligence Pipeline from community discussions.