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

  1. Run `gh api "repos/{owner}/{repo}/contents/{dir}"` manually and inspect stdout — if it is not JSON, fix the gh problem it reveals.
  2. Run `gh auth status` and re-authenticate with `gh auth login` (or fix the GH_TOKEN env var) if the token is expired/invalid.
  3. Check GH_HOST and proxy settings if a non-GitHub response (e.g. HTML) is returned.
  4. 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

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

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/07522e35ee46dd16. Report an issue: GitHub.