block / block/buzz

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

Open
#4,568 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## 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`:

```rust
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`:

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

`set_global_agent_config` returns `Result`, 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.:

```js
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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.