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

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, and use the unified ProviderError enum in 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
Server (goose-server) Provides the HTTP/WebSocket API used by the UI and external tools crates/goose-server/src/lib.rs
Agent Core (goose) Orchestrates sessions, providers, tools, security scanning and tracing 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, crates/goose/src/tracing/rate_limiter.rs
Scheduler Persists, schedules and runs recipes (cron-like jobs) crates/goose/src/scheduler.rs
Providers Adapters for OpenAI, Anthropic, Azure, etc.; errors unified in ProviderError 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
MCP Extensions Model-Context-Protocol extensions used by tools 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:

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.

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 contains a MockBatchManager pattern you can adapt. Compile Goose with the debug-tracing feature in 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. When you encounter API failures, trace the error back to the concrete provider implementation (e.g., 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 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:

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. 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:

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) prints inbound and outbound JSON messages. Cross-reference these with the server logs from 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 testscargo test -p goose
  • Run a single test filecargo test -p goose --test tool_inspection_manager_tests
  • Verify TLS handlingcargo test -p goose-server --test tls_test

The tests use a MockBatchManager that captures telemetry events. Copy this pattern from observation_layer.rs to create minimal reproduction cases for specific components like provider error handling or scheduler logic.

Example: Testing Provider Error Propagation

#[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

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 to diagnose API failures
  • Inspect 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. 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →