{"record":{"id":"660f8d3cb56f6f59","repo":"epi052/feroxbuster","slug":"json-has-no-tag-name-json-response","errorCode":null,"errorMessage":"JSON has no tag_name: {json_response}","messagePattern":"JSON has no tag_name: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/banner/container.rs","lineNumber":616,"sourceCode":"        let result = make_request(\n            &client,\n            &api_url,\n            DEFAULT_METHOD,\n            None,\n            level,\n            &handles.config,\n            tx_stats,\n        )\n        .await?;\n\n        let body = result.text().await?;\n\n        let json_response: Value = serde_json::from_str(&body)?;\n\n        let latest_version = match json_response[\"tag_name\"].as_str() {\n            Some(tag) => tag.trim_start_matches('v'),\n            None => {\n                bail!(\"JSON has no tag_name: {json_response}\");\n            }\n        };\n\n        // if we've gotten this far, we have a string in the form of X.X.X where X is a number\n        // all that's left is to compare the current version with the version found above\n\n        if latest_version == self.version {\n            // there's really only two possible outcomes if we accept that the tag conforms to\n            // the X.X.X pattern:\n            //   1. the version strings match, meaning we're up to date\n            //   2. the version strings do not match, meaning we're out of date\n            //\n            // except for developers working on this code, nobody should ever be in a situation\n            // where they have a version greater than the latest tagged release\n            self.update_status = UpdateStatus::UpToDate;\n        } else {\n            self.update_status = UpdateStatus::OutOfDate;\n        }","sourceCodeStart":598,"sourceCodeEnd":634,"githubUrl":"https://github.com/epi052/feroxbuster/blob/1f595dab5c76858d5a14fbc47dabf2563d729c62/src/banner/container.rs#L598-L634","documentation":"check_for_updates fetches the latest GitHub release metadata as JSON and extracts the `tag_name` field to compare against the current version. If the parsed JSON object has no string `tag_name` field, the function cannot determine the latest version and bails with this error. It guards against GitHub (or a proxy/mirror) returning a response that is valid JSON but not a release object.","triggerScenarios":"Calling check_for_updates (or triggering the banner update check at startup) when the HTTP endpoint returns JSON lacking a `tag_name` key — e.g. a GitHub API rate-limit/error JSON body, a non-release endpoint, or a self-hosted update URL that returns `null` or `{}`.","commonSituations":"GitHub API rate limiting (403 JSON body without tag_name), configuring a custom update-check URL that points at a non-release JSON document, network middleboxes (corporate proxies) rewriting the response, or GitHub changing/omitting tag_name for draft releases.","solutions":["Wait for the GitHub API rate limit to reset or set a GITHUB_TOKEN, since rate-limit responses lack tag_name","Verify the update-check URL points at a GitHub releases API endpoint (e.g. /repos/OWNER/REPO/releases/latest) that returns a release object","Inspect the JSON echoed in the error message to confirm what was actually returned and adjust the source/proxy accordingly","Ignore the error — it only affects the update banner and is reported as an unknown update state, not a fatal condition"],"exampleFix":"// before: raw JSON checked directly\nlet latest_version = json_response[\"tag_name\"].as_str()...;\n// after: defensive check by caller\nlet status = check_for_updates().unwrap_or(UpdateStatus::Unknown);","handlingStrategy":"fallback","validationCode":"if let Ok(v) = serde_json::from_str::<serde_json::Value>(&body) {\n    if v[\"tag_name\"].as_str().is_none() {\n        eprintln!(\"update check: response has no tag_name\");\n    }\n}","typeGuard":"fn has_tag_name(v: &serde_json::Value) -> bool { v[\"tag_name\"].as_str().is_some() }","tryCatchPattern":"match check_for_updates() {\n    Ok(status) => status,\n    Err(e) => { log::warn!(\"update check failed: {e}\"); UpdateStatus::Unknown }\n}","preventionTips":["Use the official GitHub releases API endpoint for the update check URL","Handle GitHub API rate-limit responses (403 with JSON error body) explicitly","Treat update-check failures as non-fatal and surface an 'unknown' update state","Log the offending JSON body so misconfigured URLs are easy to diagnose"],"tags":["http","json","update-check","network"],"backgroundTag":"unexpected-response-shape","analyzedSha":"1f595dab5c76858d5a14fbc47dabf2563d729c62","analyzedAt":"2026-09-13T19:33:06.208Z","contentChangedAt":"2026-09-13T19:33:06.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}