aaif-goose/goose · error

Failed to parse file info: {}

Error message

Failed to parse file info: {}

What it means

After successfully fetching the single recipe file's metadata, `serde_json::from_slice` on gh's stdout failed — the response body was not valid JSON. The directory listing call succeeded, so auth is fine; this points to a mangled response for the file-content endpoint, such as warnings injected into stdout, truncated output, or non-JSON error bodies from a proxy.

Source

Thrown at crates/goose-cli/src/recipes/github_recipe.rs:352

    let output = Command::new("gh")
        .args([
            "api",
            &format!("repos/{}/contents/{}/{}", repo, dir_name, recipe_filename),
        ])
        .set_no_window()
        .output()
        .map_err(|e| anyhow!("Failed to get recipe file content: {}", e))?;

    if !output.status.success() {
        return Err(anyhow!(
            "Failed to access recipe file: {}/{}",
            dir_name,
            recipe_filename
        ));
    }

    let file_info: Value = serde_json::from_slice(&output.stdout)
        .map_err(|e| anyhow!("Failed to parse file info: {}", e))?;

    if let Some(content_b64) = file_info.get("content").and_then(|c| c.as_str()) {
        // Decode base64 content
        use base64::{engine::general_purpose, Engine as _};
        let content_bytes = general_purpose::STANDARD
            .decode(content_b64.replace('\n', ""))
            .map_err(|e| anyhow!("Failed to decode base64 content: {}", e))?;

        let content = String::from_utf8(content_bytes)
            .map_err(|e| anyhow!("Failed to convert content to string: {}", e))?;

        // Parse the recipe content
        let (recipe, _) = parse_recipe_content(&content, Some(format!("{}/{}", repo, dir_name)))?;

        return Ok(RecipeInfo {
            name: dir_name.to_string(),
            source: RecipeSource::GitHub,
            path: format!("{}/{}", repo, dir_name),

View on GitHub (pinned to 3810898a74)

Solutions

  1. Reproduce manually: `gh api "repos/{repo}/contents/{dir}/{file}" | head -c 300` and look for non-JSON prefix lines.
  2. Remove gh aliases or wrappers (check `gh alias list`) that decorate output.
  3. Update gh to a version that keeps notices on stderr.
  4. Retry after a short wait if a transient secondary rate-limit notice was interleaved.

Example fix

# before: gh alias wraps output
$ gh alias list
api: api --paginate || echo done   # extra text pollutes stdout

# after
$ gh alias delete api
$ goose recipe info owner/repo/my-recipe
Defensive patterns

Strategy: validation

Validate before calling

# ensure the file endpoint returns pure JSON before relying on goose's parse
gh api "repos/${REPO}/contents/${DIR}/recipe.yaml" | jq -e 'has("content")' >/dev/null \
  || echo "response is not clean JSON — check gh aliases/proxies"

Try / catch

if let Err(e) = get_recipe_info(repo, dir) {
    if e.to_string().starts_with("Failed to parse file info") {
        eprintln!("gh stdout polluted — inspect `gh api .../recipe.yaml` output");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: gh emitting a deprecation or secondary-rate-limit warning line into stdout before the JSON body; a proxy or GH_HOST gateway rewriting the response; extremely large responses being truncated by pipe buffering limits.

Common situations: Corporate proxies modifying responses; gh versions that print notices to stdout instead of stderr; piping through wrappers (gh aliases, tee) that add text.

Understand the failure class

Related errors


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