> This page is for NeMo Relay, version v0.6.0.
> For other versions, use one of these documentation indexes:
> - Latest (v0.10.0) (default): https://docs.nvidia.com/nemo/relay/latest/llms.txt
> - dev: https://docs.nvidia.com/nemo/relay/dev/llms.txt
> - v0.10.0: https://docs.nvidia.com/nemo/relay/v0.10.0/llms.txt
> - v0.9.4: https://docs.nvidia.com/nemo/relay/v0.9.4/llms.txt
> - v0.8.4: https://docs.nvidia.com/nemo/relay/v0.8.4/llms.txt
> - v0.7.3: https://docs.nvidia.com/nemo/relay/v0.7.3/llms.txt
> - v0.6.0: https://docs.nvidia.com/nemo/relay/v0.6.0/llms.txt
> - v0.5.0: https://docs.nvidia.com/nemo/relay/v0.5.0/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/relay/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/relay/_mcp/server.

# Validate Plugin Configuration

> Validate NeMo Relay plugin configuration and return stable diagnostics before activation.

Use this guide when you have a plugin kind and need predictable diagnostics before the plugin installs runtime behavior.

## What You Build

Define a JSON-compatible component configuration, validate required fields and
supported values, return structured diagnostics, and confirm that disabled
components still report configuration problems before rollout.

## Configuration Shape

The canonical plugin configuration is a top-level document with `version`, `components`, and `policy`.

Each component has:

* `kind`: the plugin kind to activate.
* `enabled`: whether the component should initialize.
* `config`: the component-local JSON object passed to validation and registration.

Relay validates disabled components. This lets operators detect configuration
problems before enabling a component in a later rollout.

The top-level `policy` controls validation that Relay handles, including unknown
plugin kinds and unsupported document versions. For built-in components,
non-default `unknown_field` and `unsupported_value` settings also override the
matching component policy during host validation. When a top-level setting uses
its default value, an explicitly configured component policy remains in effect.

A custom plugin's `validate()` method controls how its own `config` fields
handle unknown fields and unsupported values. This includes in-process Python
and Node.js plugins, native plugins, and gRPC worker plugins; their validation
callbacks receive only component configuration.

The following examples create the same configuration in each supported binding:

#### Python

```python
from nemo_relay.plugin import ComponentSpec, ConfigPolicy, PluginConfig

config = PluginConfig(
    version=1,
    components=[
        ComponentSpec(
            kind="header-plugin",
            enabled=True,
            config={"header_name": "x-tenant", "value": "tenant-a"},
        )
    ],
    policy=ConfigPolicy(
        unknown_component="warn",
        unknown_field="warn",
        unsupported_value="error",
    ),
)
```

#### Node.js

```js

const config = {
  version: 1,
  components: [
    {
      kind: 'header-plugin',
      enabled: true,
      config: { header_name: 'x-tenant', value: 'tenant-a' },
    },
  ],
  policy: {
    unknown_component: 'warn',
    unknown_field: 'warn',
    unsupported_value: 'error',
  },
};
```

#### Rust

```rust
use nemo_relay::plugin::{ConfigPolicy, PluginComponentSpec, PluginConfig};

let mut component = PluginComponentSpec::new("header-plugin");
component.enabled = true;
component.config.insert("header_name".into(), "x-tenant".into());
component.config.insert("value".into(), "tenant-a".into());

let config = PluginConfig {
    version: 1,
    components: vec![component],
    policy: ConfigPolicy::default(),
};
```

## Validation Rules

Keep validation deterministic and side-effect free. Inspect configuration and
return diagnostics. Do not register middleware, open network connections,
create clients, or change process state.

Validate these areas first:

* Required fields are present.
* Field types match the supported shape.
* Your plugin reports unknown component-local fields with the diagnostic level
  its contract defines.
* Your plugin reports unsupported component-local values with the diagnostic
  level its contract defines.
* Cross-field combinations make sense.
* Sensitive values are references or secret names, not raw credentials.

Use warnings when a config can still activate but deserves operator attention. Use errors when initialization should not proceed.

## Diagnostic Shape

Diagnostics should be actionable and stable enough for tests or deployment automation:

```json
[
  {
    "level": "error",
    "code": "header-plugin.missing_header_name",
    "component": "header-plugin",
    "field": "header_name",
    "message": "config.header_name is required"
  }
]
```

Prefer stable diagnostic codes over prose-only messages. The message can improve over time; the code should remain testable.

## Validate Before Initialization

Use the validation API before initialization and fail deployment if the report contains errors.

> **Warning**
>
> This error check does not catch an enabled unknown or unregistered component
> kind. Under the default `unknown_component="warn"` policy that case is reported
> as a warning, not an error, so the check below passes while `initialize()` still
> raises for an enabled kind that is not registered. Register every enabled kind
> before initialization, or set
> `unknown_component="error"` to make validation fail on unknown kinds.

`validate()` checks only the configuration you pass to it. `initialize()` also
layers discovered `plugins.toml` configuration. A preflight report can pass
while the effective startup configuration activates or rejects other
components. Refer to [Plugin Configuration Files](/configure-plugins/plugin-configuration-files) when file discovery
participates in deployment.

Append the following validation step to the matching configuration example
above. Each example stops deployment when validation reports an error:

#### Python

```python
import nemo_relay

report = nemo_relay.plugin.validate(config)
has_errors = any(diagnostic["level"] == "error" for diagnostic in report["diagnostics"])
if has_errors:
    raise RuntimeError(report["diagnostics"])
```

#### Node.js

```js
const plugin = require('nemo-relay-node/plugin');

const report = plugin.validate(config);
const hasErrors = report.diagnostics.some((diagnostic) => diagnostic.level === 'error');
if (hasErrors) {
  throw new Error(JSON.stringify(report.diagnostics));
}
```

#### Rust

```rust
use nemo_relay::plugin::validate_plugin_config;

let report = validate_plugin_config(&config);
if report.has_errors() {
    panic!("{:?}", report.diagnostics);
}
```

## Validation Checklist

Before sharing a plugin config contract:

1. Validate the smallest correct config.
2. Validate a config with each required field missing.
3. Validate unsupported enum or mode values.
4. Validate unknown component-local fields and their diagnostic levels.
5. Validate disabled components with invalid config.
6. Confirm diagnostics identify the component and field that needs action.

## Common Issues

Check these symptoms first when the workflow does not behave as expected.

* **Config contains callables or client objects**: Keep config JSON-compatible and instantiate objects inside plugin code.
* **Disabled components skip validation**: Disabled components should still report config problems.
* **Diagnostics are hard to automate**: Add stable codes and field names.
* **Validation opens network connections**: Move runtime setup into plugin registration.

## Next Steps

Use these links to continue from this workflow into the next related task.

* Register runtime behavior with [Register Plugin Behavior](/build-plugins/language-binding/register-behavior).
* Add rollout controls with [Design Plugin Configuration](/build-plugins/language-binding/advanced-configuration).
* Review concrete validation patterns in [Code Examples](/build-plugins/language-binding/code-examples).