coleam00/Archon · error

Expected directory listing from ${url}, got a single file

Error message

Expected directory listing from ${url}, got a single file

What it means

Thrown when the GitHub contents API returns a JSON object (a single file record) instead of the expected array of directory entries. The marketplace listing code calls the contents API expecting a directory; a non-array response means the URL pointed at a file, not a directory. It guards `fetchDirectoryListing`'s contract that callers receive `GitHubContentItem[]`.

Source

Thrown at packages/cli/src/commands/workflow.ts:5110

  owner: string,
  repo: string,
  path: string,
  sha: string
): Promise<GitHubContentItem[]> {
  const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${sha}`;
  let res: Response;
  try {
    res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } });
  } catch (error) {
    const err = error as Error;
    throw new Error(`Cannot reach GitHub API: ${err.message}`);
  }
  if (!res.ok) {
    throw new Error(`GitHub API error: HTTP ${String(res.status)} from ${url}`);
  }
  const data: unknown = await res.json();
  if (!Array.isArray(data)) {
    throw new Error(`Expected directory listing from ${url}, got a single file`);
  }
  return data as GitHubContentItem[];
}

/** Download a file from raw.githubusercontent.com at a pinned SHA. */
async function downloadRawFile(
  owner: string,
  repo: string,
  filePath: string,
  sha: string
): Promise<string> {
  const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${sha}/${filePath}`;
  let res: Response;
  try {
    res = await fetch(rawUrl);
  } catch (error) {
    const err = error as Error;
    throw new Error(`Cannot fetch ${rawUrl}: ${err.message}`);

View on GitHub (pinned to 0773b97458)

Solutions

  1. Fix the directory path so it points at a folder containing the workflow YAML files, not at a file
  2. Verify with `gh api repos/<owner>/<repo>/contents/<path>` that the endpoint returns an array
  3. Update the marketplace entry's sourceUrl for that workflow
  4. Handle the single-file shape explicitly if a file URL is legitimate input

Example fix

// before
throw new Error(`Expected directory listing from ${url}, got a single file`);
// after
if (!Array.isArray(data)) {
  // treat a single-file response as a one-item listing instead of failing
  return [data as GitHubContentItem];
}
Defensive patterns

Strategy: type-guard

Validate before calling

const res = await fetch(url);
const data: unknown = await res.json();
if (!Array.isArray(data)) {
  throw new Error(`${url} is not a directory (got ${typeof data === 'object' && data ? (data as {type?:string}).type : typeof data})`);
}

Type guard

function isDirectoryListing(data: unknown): data is GitHubContentItem[] {
  return Array.isArray(data) && data.every(
    (i): i is GitHubContentItem => typeof i === 'object' && i !== null && 'name' in i && 'type' in i
  );
}

Try / catch

try {
  const items = await fetchDirectoryListing(url);
} catch (e) {
  if (e instanceof Error && e.message.includes('got a single file')) {
    // fall back to single-file handling path
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `fetchDirectoryListing` (packages/cli/src/commands/workflow.ts:5110 area) with a GitHub contents API URL whose `path` resolves to a single file, or an API endpoint that returns an object payload rather than an array.

Common situations: A marketplace `sourceUrl` or directory path in a workflow entry points at the YAML file itself instead of its containing directory; GitHub returns `{type:'file',...}` for file paths; repo layout changed so the assumed directory is now a file; a truncated/symlinked path resolves to a blob.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/5ef878fd7693d899. Report an issue: GitHub.