Skip to content

Agent defaults: "Couldn't save." discards the backend validation message, making the failure undiagnosable #4568

Description

@jimparkins

Summary

AgentDefaultsEditor discards the backend's validation message and shows a bare "Couldn't save." The backend's reason is accurate and actionable — it just never reaches the user.

Result: a save that can never succeed, with no indication of why, anywhere. No app log, no relay log (even at DEBUG), no config file touched.

Reproduce

  1. Put a derived provider/model key into the global agent config's env_vars — e.g. GOOSE_PROVIDER or GOOSE_MODEL (easy to do if you have edited global-agent-config.json directly, e.g. as a workaround for a provider issue).
  2. Open Agents → Agent defaults, change the harness or model, press Save defaults.
  3. Every save fails with Couldn't save. and no further detail.

Cause

The backend correctly rejects it — desktop/src-tauri/src/managed_agents/global_config/mod.rs:113:

if !derived.is_empty() {
    return Err(format!(
        "the following keys must be set via the structured provider/model fields, \
         not as env vars: {}",
        derived.join(", ")
    ));
}

against DERIVED_PROVIDER_MODEL_ENV_KEYS (GOOSE_MODEL, GOOSE_PROVIDER, BUZZ_AGENT_MODEL, BUZZ_AGENT_PROVIDER).

The rule itself is right — Buzz derives those vars from the structured fields, so allowing both would create two sources of truth. The problem is purely that the message is thrown away in desktop/src/features/agents/ui/AgentDefaultsEditor.tsx:233:

} catch (err) {
  setSaveState("error");
  setSaveError(typeof err === "string" ? err : "Couldn't save.");
}

set_global_agent_config returns Result<GlobalAgentConfigSaveResult, String>, so the reason is a string on the Rust side — but whatever reaches the catch fails the typeof err === "string" test (Tauri appears to wrap it), so the fallback always wins.

Suggested fix

Unwrap the Tauri error rather than testing it as a bare string, e.g.:

const message =
  typeof err === "string" ? err :
  (err as { message?: string })?.message ?? "Couldn't save.";
setSaveError(message);

Even surfacing String(err) would be a large improvement over the current dead end.

Impact

The validation is a guard rail users are quite likely to hit — anyone who has hand-edited global-agent-config.json to work around a provider problem will land on it. As shipped, the only way to discover the cause is to read the Rust source.

Environment

  • Buzz Desktop 0.5.x, macOS arm64
  • Relay: self-hosted, built from source

Related

Same family as #3636 and #4278 — a correct signal produced internally, then discarded before it reaches the operator.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions