aaif-goose/goose · error
Failed to parse directory contents: {}
Error message
Failed to parse directory contents: {} What it means
Raised while listing a recipe directory from GitHub: goose shells out to `gh api repos/{repo}/contents/{dir}` and parses stdout with serde_json::from_slice. This error means gh exited successfully but printed bytes that are not valid JSON. Usually gh wrote an auth prompt, a warning, or nothing to stdout while the real error went to stderr.
Source
Thrown at crates/goose-cli/src/recipes/github_recipe.rs:310
}
fn check_github_directory_for_recipe(repo: &str, dir_name: &str) -> Result<RecipeInfo> {
use serde_json::Value;
use std::process::Command;
// Check directory contents for recipe files
let output = Command::new("gh")
.args(["api", &format!("repos/{}/contents/{}", repo, dir_name)])
.set_no_window()
.output()
.map_err(|e| anyhow!("Failed to check directory contents: {}", e))?;
if !output.status.success() {
return Err(anyhow!("Failed to access directory: {}", dir_name));
}
let contents: Value = serde_json::from_slice(&output.stdout)
.map_err(|e| anyhow!("Failed to parse directory contents: {}", e))?;
if let Some(items) = contents.as_array() {
for item in items {
if let Some(name) = item.get("name").and_then(|n| n.as_str()) {
if RECIPE_FILE_EXTENSIONS
.iter()
.any(|ext| name == format!("recipe.{}", ext))
{
// Found a recipe file, get its content
return get_github_recipe_info(repo, dir_name, name);
}
}
}
}
Err(anyhow!("No recipe file found in directory: {}", dir_name))
}
View on GitHub (pinned to 3810898a74)
Solutions
- Run `gh api "repos/{owner}/{repo}/contents/{dir}"` manually and inspect stdout — if it is not JSON, fix the gh problem it reveals.
- Run `gh auth status` and re-authenticate with `gh auth login` (or fix the GH_TOKEN env var) if the token is expired/invalid.
- Check GH_HOST and proxy settings if a non-GitHub response (e.g. HTML) is returned.
- Update gh to a current version if output formatting differs.
Example fix
// before: gh token expired, gh prints prompt text to stdout
$ gh api repos/owner/repo/contents/recipes
To get started with GitHub CLI, please run: gh auth login
// after
$ gh auth login
$ gh api repos/owner/repo/contents/recipes
[{"name": "my-recipe", "path": "recipes/my-recipe", ...}] Defensive patterns
Strategy: validation
Validate before calling
# pre-flight before goose recipe commands that hit GitHub
gh auth status >/dev/null 2>&1 || gh auth login
gh api "repos/${REPO}/contents/${DIR}" >/dev/null && echo "directory listing is valid JSON" Try / catch
if let Err(e) = load_recipe_from_github(repo, dir) {
if e.to_string().starts_with("Failed to parse directory contents") {
eprintln!("gh returned non-JSON; check `gh auth status` and proxies");
}
return Err(e);
} Prevention
- Keep `gh auth token` valid; scripts should run `gh auth status` as a preflight.
- Don't wrap gh with aliases or pipes that add text to stdout.
- Pin a known-good gh version in CI images.
When it happens
Trigger: Running `goose recipe` commands that load recipes from a GitHub repo when `gh api repos/{repo}/contents/{dir_name}` returns non-JSON stdout: expired token emitting an interactive `gh auth login` prompt text, a corporate proxy returning an HTML error page, or empty stdout from a misbehaving gh wrapper.
Common situations: Expired or partially configured `gh auth login` state; GH_TOKEN/ GITHUB_TOKEN env var set to an invalid value that overrides keyring auth; proxies or GH_HOST misconfiguration; gh version mismatches after OS upgrades.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse file info: {}
- Failed to access recipe file: {}/{}
- Failed to parse OpenAI evaluation response after {max_retrie
- Failed to parse tie-breaker response after {max_retries} att
- No recipe file found in {} (looked for extensions: {:?})
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/07522e35ee46dd16.
Report an issue: GitHub.