# How Music Assistant Validates Provider Configuration: The Config Schema System Explained

> Learn how Music Assistant validates provider configuration using its schema system. Discover auto-generated JSON schemas and Pydantic validation for type safety and custom constraints.

- Repository: [Music Assistant/server](https://github.com/music-assistant/server)
- Tags: deep-dive
- Published: 2026-06-17

---

**Music Assistant validates provider configuration through a schema-driven architecture where each provider defines `ConfigEntry` objects that automatically generate JSON schemas for UI rendering and enforce type safety through Pydantic validation, with optional custom validators for provider-specific constraints.**

Music Assistant treats every music service, player, and metadata provider as a plugin with declarative configuration schemas. In the `music-assistant/server` repository, the provider configuration validation system combines static manifests with dynamic Python functions to ensure type safety while maintaining flexible, provider-specific validation logic.

## The Provider Manifest: Static Metadata Foundation

### Manifest Structure and Discovery

Every provider includes a [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) file that declares its domain, type, and capabilities. For example, the Spotify provider defines its metadata at [`music_assistant/providers/spotify/manifest.json`](https://github.com/music-assistant/server/blob/main/music_assistant/providers/spotify/manifest.json). This static file contains the provider type (music, player, or metadata), domain identifier, required Python packages, and the `multi_instance` flag that determines whether multiple instances can coexist.

The manifest drives the discovery system during server startup, enables the UI to display provider names and icons, and allows the installer to pull optional dependencies before the provider initializes.

## Dynamic Configuration with `get_config_entries()`

### ConfigEntry Types and Attributes

Providers implement the asynchronous `get_config_entries()` function to define configurable fields dynamically. This function returns a tuple of `ConfigEntry` objects imported from the external `music_assistant_models` package. Each entry specifies the field key, type from the `ConfigEntryType` enum (such as `STRING`, `SECURE_STRING`, `BOOLEAN`, `ACTION`, or `LABEL`), default values, and UI presentation hints.

The `ConfigEntry` class functions as a Pydantic model, enabling automatic type checking and validation when instantiated. Key attributes include `required` to enforce non-empty values, `hidden` to conditionally omit fields from the UI, and `category` to group related settings logically.

Example from [`music_assistant/providers/spotify/__init__.py`](https://github.com/music-assistant/server/blob/main/music_assistant/providers/spotify/__init__.py):

```python
async def get_config_entries(
    mass: MusicAssistant,
    instance_id: str | None = None,
    action: str | None = None,
    values: dict[str, ConfigValueType] | None = None,
) -> tuple[ConfigEntry, ...]:
    return (
        CONF_ENTRY_UNOFFICIAL_PROVIDER,
        ConfigEntry(
            key="label_text",
            type=ConfigEntryType.LABEL,
            label=label_text
        ),
        ConfigEntry(
            key=CONF_REFRESH_TOKEN_GLOBAL,
            type=ConfigEntryType.SECURE_STRING,
            # ...

        ),
        ConfigEntry(
            key=CONF_ACTION_AUTH,
            type=ConfigEntryType.ACTION,
            action=CONF_ACTION_AUTH,
            hidden=global_authenticated
        ),
    )

```

## The Validation Pipeline

### Schema Generation for the UI

The web server converts `ConfigEntry` objects into OpenAPI-compatible JSON schemas for front-end consumption. The conversion logic resides in [`music_assistant/controllers/webserver/api_docs.py`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/webserver/api_docs.py), specifically within the `_get_type_schema()` function. This routine maps `ConfigEntryType` enum values to appropriate JSON schema types, enabling the React-based UI to render text inputs, secure password fields, and action buttons dynamically based on the provider's declared schema.

### Server-Side Validation with Pydantic

When users save configuration changes, the server receives the payload at [`music_assistant/controllers/webserver/controller.py`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/webserver/controller.py) in the `_handle_config_set` method. The core loads the current `ConfigEntry` definitions for the provider and validates each value using Pydantic's parsing methods. Because `ConfigEntry` is a Pydantic model, this automatically enforces that **SECURE_STRING** fields contain strings, **BOOLEAN** fields contain true/false values, and that entries marked `required` are not empty.

### Custom Provider Validators

Providers can attach custom validation logic to specific fields through the `validate` parameter. These functions execute after Pydantic type checking completes, allowing providers to enforce domain-specific constraints like network port availability or API token format validation.

Example from [`music_assistant/providers/vban_receiver/__init__.py`](https://github.com/music-assistant/server/blob/main/music_assistant/providers/vban_receiver/__init__.py):

```python
ConfigEntry(
    key="stream_name",
    type=ConfigEntryType.STRING,
    validate=_validate_stream_name,  # Custom validator

    # ...

)

```

Custom validators must return `True` for valid values or raise `ValueError` with descriptive messages. The web server catches these exceptions and translates them into user-visible error notifications in the configuration UI.

## Configuration Persistence and Lifecycle

Once validation passes, configurations are serialized to JSON and stored in the SQLite database at `$HOME/.musicassistant/settings`. The database schema preserves type consistency by storing the `ConfigEntryType` alongside each JSON-encoded value. During provider initialization, the factory method in [`music_assistant/models/provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/provider.py) retrieves these values and passes them to the provider class, completing the lifecycle from schema definition to runtime usage.

Providers may also perform runtime validation within their implementation methods to verify that external resources remain accessible using the stored configuration values.

## Summary

- **Manifest-driven discovery**: Each provider ships a [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) file that declares static metadata, dependencies, and multi-instance capabilities.
- **Dynamic schema generation**: The `get_config_entries()` function returns `ConfigEntry` objects that automatically generate OpenAPI-compatible JSON schemas for the React front-end.
- **Pydantic type validation**: `ConfigEntry` leverages Pydantic models to enforce type safety for strings, booleans, secure tokens, and action triggers.
- **Custom validation hooks**: Providers can implement field-specific validator functions that raise `ValueError` for domain-specific constraints like network availability.
- **SQLite persistence**: Validated configurations are stored as JSON in the settings table with type annotations, ensuring reliable retrieval during server startup and provider initialization.

## Frequently Asked Questions

### What is the difference between ConfigEntryType.STRING and ConfigEntryType.SECURE_STRING?

`ConfigEntryType.SECURE_STRING` masks sensitive values like passwords and API tokens in the UI and server logs, while `ConfigEntryType.STRING` displays values in plain text. Both enforce string type validation through Pydantic, but the secure variant triggers additional front-end rendering logic to protect credential visibility and prevent accidental exposure in debug output.

### How does Music Assistant handle validation errors from custom provider validators?

When a custom validator function attached to a `ConfigEntry` raises a `ValueError`, the web server catches the exception in [`controllers/webserver/controller.py`](https://github.com/music-assistant/server/blob/main/controllers/webserver/controller.py) and translates the error message into a user-friendly notification displayed in the configuration UI. This allows providers to communicate specific requirements, such as port availability or format restrictions, directly to users during the configuration process.

### Can a provider hide configuration fields based on other settings?

Yes, providers use the `hidden` attribute on `ConfigEntry` objects to conditionally omit fields from the UI dynamically. For example, the Spotify provider hides the authentication action button when authentication is already complete, and shows it only when credentials are needed. The `get_config_entries()` function recalculates visibility each time the configuration panel loads, enabling responsive UI states based on current values.

### Where are provider configurations stored after validation?

Validated configurations are persisted in an SQLite database located at `$HOME/.musicassistant/settings`. The `value` column stores JSON-encoded configuration data, while the `type` column preserves the `ConfigEntryType` enum value, ensuring type consistency when configurations are reloaded during server startup or provider initialization.