# How to Debug Issues Within the Goose Project: A Complete Guide

> Debug Goose project issues effectively. Enable trace logging use ObservationLayer telemetry and the ProviderError enum to pinpoint API failures in your aaif-goose/goose application.

- Repository: [goose/goose](https://github.com/aaif-goose/goose)
- Tags: how-to-guide
- Published: 2026-04-07

---

**To debug issues in Goose, enable trace-level logging with `RUST_LOG=trace`, inspect the `ObservationLayer` telemetry in [`crates/goose/src/tracing/observation_layer.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/tracing/observation_layer.rs), and use the unified `ProviderError` enum in [`crates/goose/src/providers/errors.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/providers/errors.rs) to isolate API failures.**

Goose is a multi-layered Rust application combining a **CLI**, **Electron UI**, and **backend server**. Understanding its architecture is essential to debug issues within the Goose project effectively. This guide covers the specific source files, tracing mechanisms, and debugging strategies implemented in the aaif-goose/goose repository.

## Understanding Goose's Architectural Layers

Before debugging, identify which layer produces the error. Goose organizes functionality into distinct crates:

| Layer | Responsibility | Key Source Files |
|-------|----------------|------------------|
| **CLI (`goose-cli`)** | Parses user commands, drives the scheduler, prints diagnostic output | [`crates/goose-cli/src/session/mod.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose-cli/src/session/mod.rs) |
| **Server (`goose-server`)** | Provides the HTTP/WebSocket API used by the UI and external tools | [`crates/goose-server/src/lib.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose-server/src/lib.rs) |
| **Agent Core (`goose`)** | Orchestrates sessions, providers, tools, security scanning and tracing | [`crates/goose/src/session/mod.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/session/mod.rs) |
| **Tracing & Telemetry** | Builds Langfuse-compatible events for every span, event and trace | [`crates/goose/src/tracing/observation_layer.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/tracing/observation_layer.rs), [`crates/goose/src/tracing/rate_limiter.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/tracing/rate_limiter.rs) |
| **Scheduler** | Persists, schedules and runs recipes (cron-like jobs) | [`crates/goose/src/scheduler.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/scheduler.rs) |
| **Providers** | Adapters for OpenAI, Anthropic, Azure, etc.; errors unified in `ProviderError` | [`crates/goose/src/providers/mod.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/providers/mod.rs) |
| **Security Scanners** | Optional ML-based and pattern-based scanning of tool input/output | [`crates/goose/src/security/mod.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/security/mod.rs) |
| **MCP Extensions** | Model-Context-Protocol extensions used by tools | [`crates/goose-mcp/src/lib.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose-mcp/src/lib.rs) |

## Enabling Trace Logging and Telemetry Inspection

Goose uses the **`tracing`** crate with a custom **`ObservationLayer`** that converts every span into a Langfuse-compatible event. When you debug issues within the Goose project, start by enabling maximum verbosity:

```bash
RUST_LOG=trace RUST_LOG_STYLE=always goose <subcommand>

```

The `tracing-subscriber` default in `goose-cli` reads the `RUST_LOG` environment variable. All spans starting with `goose::` are emitted via `ObservationLayer::enabled` according to the source in [`crates/goose/src/tracing/observation_layer.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/tracing/observation_layer.rs).

You will see specific event types in the output:

- **`trace-create`** – Creates a trace ID when a session starts
- **`observation-create`** – Opens a new span (e.g., a provider call)
- **`span-update`** – Updates from `on_record` containing input/output fields
- **`observation-update`** – Fires when a span closes, containing `endTime`

### Inspecting Raw Telemetry Events

If you need to capture events to a file instead of stdout, replace the default `BatchManager` with a mock implementation. The test file [`observation_layer.rs`](https://github.com/aaif-goose/goose/blob/main/observation_layer.rs) contains a `MockBatchManager` pattern you can adapt. Compile Goose with the `debug-tracing` feature in [`Cargo.toml`](https://github.com/aaif-goose/goose/blob/main/Cargo.toml) to inject this mock at runtime and write events to disk for analysis.

## Debugging Provider Errors and API Failures

All LLM providers return a unified **`ProviderError`** defined in [`crates/goose/src/providers/errors.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/providers/errors.rs). When you encounter API failures, trace the error back to the concrete provider implementation (e.g., [`crates/goose/src/providers/openai.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/providers/openai.rs)).

Common variants include:

- **`ContextLengthExceeded`** – The prompt exceeds the model's token limit
- **`RateLimited`** – The API returned HTTP 429; the error includes a `retry_after` hint

Most providers use a `send_request` helper that decorates raw HTTP errors with these enum variants. Check the specific provider file to inspect how the error is constructed and what context is preserved.

## Troubleshooting the Scheduler and Cron Jobs

The **Scheduler** stores jobs in a SQLite file called `scheduler.db`. When recipes fail to execute or disappear, examine [`crates/goose/src/scheduler.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/scheduler.rs) for these specific error variants:

- **`SchedulerError::JobNotFound`** – The job ID does not exist in the database
- **`SchedulerError::CronParseError`** – The cron expression is invalid

The scheduler uses the `cron` crate for parsing. Test expressions directly using the `Scheduler::create_cron_task` method or verify them with an online validator.

Enable SQL query logging to spot missing migrations or corrupted rows:

```bash
SQLX_DEBUG=true RUST_LOG=trace goose schedule list

```

## Debugging Security Scanner Initialization

If you enable the ML scanner, initialization failures appear in [`crates/goose/src/security/mod.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/security/mod.rs). Look for the log message `ML scanning requested but failed to initialize…`. The system falls back to pattern-only scanning, but a missing model file will surface as an explicit error string.

Verify that model artifacts exist in the directory specified by the `SECURITY_MODEL_PATH` environment variable before enabling the scanner.

## Capturing UI-to-Server WebSocket Traffic

The Electron UI communicates with the backend over a local WebSocket. To debug issues within the Goose project that appear only in the interface, capture the full message flow:

```bash
RUST_LOG=trace RUST_LOG_STYLE=always goose server &
WEB_SOCKET_DEBUG=1 pnpm start   # inside ui/desktop

```

The `WEB_SOCKET_DEBUG` flag (checked in [`ui/desktop/src/main.ts`](https://github.com/aaif-goose/goose/blob/main/ui/desktop/src/main.ts)) prints inbound and outbound JSON messages. Cross-reference these with the server logs from [`crates/goose-server/src/lib.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose-server/src/lib.rs) to identify where the communication breaks down.

## Writing Targeted Tests to Reproduce Issues

Goose ships with a comprehensive test suite that doubles as a sandbox for reproducing bugs. Use these commands to isolate failures:

- **Run all tests** – `cargo test -p goose`
- **Run a single test file** – `cargo test -p goose --test tool_inspection_manager_tests`
- **Verify TLS handling** – `cargo test -p goose-server --test tls_test`

The tests use a **`MockBatchManager`** that captures telemetry events. Copy this pattern from [`observation_layer.rs`](https://github.com/aaif-goose/goose/blob/main/observation_layer.rs) to create minimal reproduction cases for specific components like provider error handling or scheduler logic.

### Example: Testing Provider Error Propagation

```rust
#[tokio::test]
async fn test_context_length_error_is_propagated() {
    let provider = goose::providers::openai::OpenAiProvider::new("dummy-key".into());
    let long_prompt = "x".repeat(10_000); // exceed token limit

    let result = provider.send_message(&long_prompt).await;
    assert!(matches!(result, Err(goose::providers::errors::ProviderError::ContextLengthExceeded(_))));
}

```

### Example: Debugging Cron Expressions

```rust
use goose::scheduler::Scheduler;
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    let scheduler = Scheduler::new_default().await?;
    // This will print a detailed parsing error if the cron string is invalid
    scheduler.create_cron_task(
        goose::scheduler::ScheduledJob {
            id: "demo".into(),
            cron: "0 * * * *".into(),
            recipe: "demo.yaml".into(),
            enabled: true,
        }
    )?;
    Ok(())
}

```

## Summary

To effectively debug issues within the Goose project, remember these key strategies:

- **Enable `RUST_LOG=trace`** to see every span and event emitted by the `ObservationLayer`
- **Check `ProviderError`** variants in [`crates/goose/src/providers/errors.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/providers/errors.rs) to diagnose API failures
- **Inspect [`scheduler.rs`](https://github.com/aaif-goose/goose/blob/main/scheduler.rs)** and use `SQLX_DEBUG=true` for database-related job issues
- **Use `WEB_SOCKET_DEBUG=1`** when UI behavior differs from CLI behavior
- **Leverage the `MockBatchManager` pattern** in tests to capture and inspect telemetry events without external dependencies

## Frequently Asked Questions

### How do I enable verbose logging in Goose?

Set the `RUST_LOG=trace` environment variable before running any Goose command. For colorized output that persists in log files, add `RUST_LOG_STYLE=always`. This activates the `tracing-subscriber` configuration in `goose-cli` and emits all spans that start with `goose::` through the `ObservationLayer`.

### Where are provider errors defined in Goose?

All provider errors are unified in the **`ProviderError`** enum located in [`crates/goose/src/providers/errors.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/providers/errors.rs). This file defines variants like `ContextLengthExceeded` and `RateLimited` that wrap specific API failures from OpenAI, Anthropic, Azure, and other backends.

### How can I debug cron expressions in the Goose scheduler?

The scheduler uses the `cron` crate to parse expressions. If you see `SchedulerError::CronParseError` in [`crates/goose/src/scheduler.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose/src/scheduler.rs), validate your expression by calling `Scheduler::create_cron_task` directly in a test binary or use an online cron validator. Enable `SQLX_DEBUG=true` to see the underlying SQL queries if jobs fail to persist.

### How do I capture WebSocket traffic between the UI and server?

Start the server with `RUST_LOG=trace`, then launch the Electron UI with `WEB_SOCKET_DEBUG=1 pnpm start` from the `ui/desktop` directory. This prints raw JSON messages to the console, allowing you to correlate UI actions with server-side traces in [`crates/goose-server/src/lib.rs`](https://github.com/aaif-goose/goose/blob/main/crates/goose-server/src/lib.rs).