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 startsobservation-create– Opens a new span (e.g., a provider call)span-update– Updates fromon_recordcontaining input/output fieldsobservation-update– Fires when a span closes, containingendTime
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 limitRateLimited– The API returned HTTP 429; the error includes aretry_afterhint
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 databaseSchedulerError::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 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 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=traceto see every span and event emitted by theObservationLayer - Check
ProviderErrorvariants incrates/goose/src/providers/errors.rsto diagnose API failures - Inspect
scheduler.rsand useSQLX_DEBUG=truefor database-related job issues - Use
WEB_SOCKET_DEBUG=1when UI behavior differs from CLI behavior - Leverage the
MockBatchManagerpattern 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →