zeroclaw-labs/zeroclaw · warning · DiagItem

{} (at {})

Error message

{} (at {})

What it means

Not a single check but the aggregation point: `check_config_semantics` forwards every warning from `Config::collect_warnings()` — the single source of truth shared with the gateway API and `Config::validate()` tracing — formatting each as `<message> (at <config path>)`. Typical warnings behind this wrapper are dangling model fallback references and `wire_api` misuse. Doctor deliberately does not duplicate those checks; it only re-reports them with their config path.

Source

Thrown at crates/zeroclaw-runtime/src/doctor/mod.rs:1381

        let provider_ref = agent.model_provider.as_str();
        if provider_ref.is_empty() {
            continue;
        }
        if let Some(reason) = provider_validation_error(config, provider_ref) {
            items.push(DiagItem::warn(
                cat,
                format!(
                    "agent \"{name}\" uses invalid model_provider \"{provider_ref}\": {reason}",
                ),
            ));
        }
    }

    // Non-fatal config warnings — dangling fallback refs, wire_api misuse, etc.
    // Source of truth: `Config::collect_warnings()` (same signal as gateway API
    // and `Config::validate()` tracing). Do not duplicate checks here.
    for warning in config.collect_warnings() {
        items.push(DiagItem::warn(
            cat,
            format!("{} (at {})", warning.message, warning.path),
        ));
    }
}

fn check_web_dist_dir(config: &Config, items: &mut Vec<DiagItem>) {
    let cat = "config";
    match config.gateway.web_dist_dir.as_deref() {
        None => {}
        Some(value) => match web_dist_dir_expansion_reason_key(value) {
            None => {}
            Some(reason_key) => {
                let reason = crate::i18n::get_required_cli_string(reason_key);
                let message = crate::i18n::get_required_cli_string_with_args(
                    "cli-doctor-web-dist-dir-expansion-warning",
                    &[("path", value), ("reason", reason.as_str())],
                );

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Read the message together with the `(at <path>)` suffix — the path names the exact config key to fix.
  2. Fix the referenced key (restore the missing provider, correct the dangling fallback, set a valid `wire_api`).
  3. Re-run `zeroclaw doctor`; the same warning source feeds `Config::validate()` tracing and the gateway API, so a clean doctor means those surfaces are clean too.
Defensive patterns

Strategy: validation

Validate before calling

for warning in config.collect_warnings() {
    eprintln!("config warning at {}: {}", warning.path, warning.message);
}

Prevention

When it happens

Trigger: Running `zeroclaw doctor`/`diagnose` on any config where `collect_warnings()` yields at least one entry, e.g. a `fallback` naming a provider that does not exist, or a `wire_api` value that does not fit the configured provider type.

Common situations: Renaming or deleting a provider while a fallback still points at the old name; switching a provider between chat/completions styles without updating `wire_api`; hand-editing config keys doctor's own checks do not cover.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/d02fdd87d777ee3f. Report an issue: GitHub.