aaif-goose / aaif-goose/goose

Recipe validation is inconsistent across three paths: manage_schedule reports "Invalid YAML" for valid YAML, and schedule add does not validate at all

Open
#11,227 12 comments 0 reactions 1 assignee Claimed by @DOsinga View on GitHub
Dominant language
Rust
Stars
54.2k
Forks
6.2k
Avg merge
3d 2h
Merged PRs (30d)
262

Description

**Version:** goose 1.46.0 (Goose.app and its bundled CLI), macOS 26.5.1, x86_64

Split out of #11164 at @A1exZabr's suggestion — it's a different subsystem and a different failure, and it stands on its own. @A1exZabr independently reproduced this on 1.46.0.

**Context on the reporter:** I'm not a developer. I'm using Goose to build a personal, fully local, automated home assistant on my own machine, and I found and investigated this with the help of Claude Code. I hit it by asking my assistant for a daily reminder and watching it fail in a way it couldn't recover from.

## Summary

The same file gets three different verdicts from three code paths in the same binary. The file below is well-formed YAML — it parses cleanly under an independent parser — but is not a valid Goose recipe, because it's missing `title`:

```yaml
name: drink_warm_water
run:
command: |
echo "Drink warm water"
schedule:
cron: "0 6 * * *"
timezone: "Asia/Kolkata"
```

| Path | Result |
|---|---|
| `goose recipe validate` | `✗ recipe file is invalid: missing field 'title'` |
| `platform__manage_schedule` (`action: create`) | `-32603: Invalid YAML recipe` |
| `goose schedule add` | **accepted silently** — job created, listed as `IDLE` |

## Two distinct problems

### 1. `manage_schedule` reports the wrong layer and discards the reason

`Invalid YAML recipe` is wrong on both counts: the YAML is valid, and the actual reason — a missing required field — is thrown away. The same binary produces `missing field 'title'` on the other two paths, so the information exists and is simply not carried through.

This matters most for the caller that can act on it. `manage_schedule` is the tool an *agent* calls, and an agent is uniquely positioned to read a precise error and fix the file itself. Instead it gets strictly less diagnostic information than a human running the CLI.

**What that looked like in practice.** I asked my assistant to set up a daily 6am reminder. It wrote the recipe above, using a schema it invented — entirely its own mistake, not a Goose bug. It called `manage_schedule`, got `Invalid YAML recipe`, and had no idea what was wrong. It edited the file, retried with the same invented schema, failed identically, then gave up and offered me three manual workarounds. Had the error said `missing field 'title'`, the retry would very likely have succeeded.

The user-visible outcome: I asked for a reminder and got an explanation of why I couldn't have one.

### 2. `goose schedule add` performs no validation

```
$ goose schedule add --schedule-id yamlerrtest --cron "0 6 * * *" --recipe-source ./bad.yaml
✅ Using standard 5-field cron format: 0 6 * * *
Scheduled job 'yamlerrtest' added.

$ goose schedule list
- ID: yamlerrtest
Status: ⏹️ IDLE
Cron: 0 6 * * *
Last Run: Never
```

It copies the file into `scheduled_recipes/` and reports success. The job sits in the schedule looking healthy, and fails only when its cron fires:

```
$ goose schedule run-now --schedule-id yamlerrtest
Error: Failed to run schedule 'yamlerrtest' now:
AnyhowError(Job 'yamlerrtest' failed: Invalid recipe: missing field `title`)
```

Note that the run-time error *does* carry the precise reason. So of the three paths, the two that could prevent the problem are the two that don't report it usefully, and the one that reports it well is the one that runs at 6am when nobody is watching.

For a desktop user, a scheduled job that fails at its cron time fails somewhere they will never look. (Related: #11164 covers what that silent-failure state looks like once you're in it.)

## Expected

- `manage_schedule` should return the same error the validator produces, naming the field.
- `schedule add` should validate the recipe before accepting the job, and refuse with that same message.

Neither requires new diagnostics — only carrying through the message Goose already generates.

## Reproduction

1. Save the YAML above as `bad.yaml`.
2. `goose recipe validate bad.yaml` → `missing field 'title'`.
3. Ask an agent session to schedule it, or call `platform__manage_schedule` with `action: create` → `-32603: Invalid YAML recipe`.
4. `goose schedule add --schedule-id t --cron "0 6 * * *" --recipe-source bad.yaml` → succeeds.
5. `goose schedule run-now --schedule-id t` → fails with `missing field 'title'`.

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.