jdx/mise · error
{rel} is not a directory of the repository
Error message
{rel} is not a directory of the repository What it means
packslip's fetch_repo_dir downloads a directory listing of a repo path via the GitHub API. It expects the JSON response to be an array of directory entries; if the API returns anything else (e.g. an object describing a single file, or an error payload), it means the requested path is not a directory in that repository at that ref. The bail conveys that the path must point at a directory to fetch its files.
Source
Thrown at src/packslip.rs:483
commit: &str,
rel: &str,
dest: &Path,
pr: &dyn SingleReport,
) -> Result<()> {
let url = format!(
"https://api.github.com/repos/{repo}/contents/{}?ref={commit}",
url_path(rel)
);
// The client asks for the raw media type on every contents URL, which
// is right for a file body and wrong for a directory listing.
let mut headers = github::get_headers(&url)?;
headers.insert(
reqwest::header::ACCEPT,
HeaderValue::from_static("application/vnd.github+json"),
);
let listing: serde_json::Value = HTTP_FETCH.json_with_headers(&url, &headers).await?;
let Some(entries) = listing.as_array() else {
bail!("{rel} is not a directory of the repository");
};
file::create_dir_all(dest)?;
for entry in entries {
let Some(name) = entry["name"].as_str() else {
continue;
};
if !file::is_plain_file_name(name) {
continue;
}
match entry["type"].as_str() {
Some("dir") => {
Box::pin(fetch_repo_dir(
repo,
commit,
&format!("{rel}/{name}"),
&dest.join(name),
pr,
))View on GitHub (pinned to afd2eddd3a)
Solutions
- Verify the `rel` path in the manifest is a directory that exists in the repo at the requested ref (check on GitHub).
- Confirm the ref/commit/tag being fetched still contains that directory; update to a ref where it exists.
- If the target is a single file, use the file-fetch path instead of a directory fetch.
- Check for GitHub API error responses (rate limiting, auth) that can replace the array with an error object; set a token if rate limited.
Example fix
// before: manifest points at a single file as a dir fetch_dir = "src/packslip.rs" // after fetch_dir = "src"
Defensive patterns
Strategy: validation
Validate before calling
async fn is_repo_dir(rel: &str, ref_: &str) -> bool {
// GitHub contents API returns an array for directories, an object for files
let listing = list_repo_dir(rel, ref_).await.ok();
matches!(listing, Some(serde_json::Value::Array(_)))
} Type guard
let Some(entries) = listing.as_array() else { return Err(...); }; Try / catch
match fetch_repo_dir(rel, ref).await {
Err(e) if e.to_string().contains("is not a directory") => eprintln!("{rel} is not a dir at {ref}; check the manifest path"),
Ok(entries) => use_entries(entries),
Err(e) => return Err(e),
} Prevention
- Point directory fetches only at directories; list file paths separately.
- Pin the ref and verify the path exists at that ref before adding it to a manifest.
- Watch for GitHub API error payloads (auth/rate limit) masquerading as 'not a directory'.
When it happens
Trigger: Calling fetch_repo_dir (directly or via fetch_files) with a `rel` path that is a single file, a nonexistent path, or a repo/ref that returns a non-array listing from the GitHub contents endpoint.
Common situations: A packslip manifest points at a file instead of a directory; the file was renamed or deleted upstream so the path 404s and the API returns an error object instead of an array; the ref (tag/commit) no longer contains the directory.
Related errors
- the release list in github.com/{repo} is for {}, not {projec
- github.com/{repo} has no release {} carrying {asset_name}; m
- remote action manifest ETag does not match its body
- Got HTML instead of text from {}
- brew-cask: unsupported tap URL for '{name}'; only GitHub tap
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/9806623164c39aba.
Report an issue: GitHub.