can1357/oh-my-pi · error · Error

Cloned repository ${url}: ${(err as Error).message} (source:

Error message

Cloned repository ${url}: ${(err as Error).message} (source: ${source})

What it means

cloneAndReadCatalog clones a git-hosted marketplace, reads and validates the catalog, and throws this wrapper error if any step fails, cleaning up the temp clone first. The original failure (clone error, missing catalog file, parse error) is preserved as the message suffix and error cause.

Source

Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/fetcher.ts:302

 *
 * Clones to a temporary directory and reads the catalog. The caller is
 * responsible for promoting the clone to its final cache location via
 * `promoteCloneToCache` after any duplicate/drift checks pass.
 */
async function cloneAndReadCatalog(url: string, source: string, cacheDir: string): Promise<FetchResult> {
	const tmpDir = path.join(cacheDir, `.tmp-clone-${Date.now()}`);
	await fs.mkdir(cacheDir, { recursive: true });

	logger.debug(`[marketplace] cloning ${url} → ${tmpDir}`);
	await vcs.clone(url, tmpDir, { timeoutMs: GIT_CLONE_TIMEOUT_MS });

	try {
		const { displayPath, content } = await readMarketplaceCatalog(tmpDir, { relativeDisplayPaths: true });
		const catalog = parseMarketplaceCatalog(content, displayPath);
		return { catalog, clonePath: tmpDir };
	} catch (err) {
		await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});
		throw new Error(`Cloned repository ${url}: ${(err as Error).message} (source: ${source})`, { cause: err });
	}
}

/**
 * Promote a temporary clone directory to its final cache location.
 *
 * Callers should invoke this only after duplicate/drift checks pass.
 * Removes any existing directory at the target path before renaming.
 */
export async function promoteCloneToCache(tmpDir: string, cacheDir: string, name: string): Promise<string> {
	const finalDir = path.join(cacheDir, name);
	await fs.rm(finalDir, { recursive: true, force: true });
	await fs.rename(tmpDir, finalDir);
	return finalDir;
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the trailing message and cause: if it's a clone error, verify the URL exists and you have access (`git clone <url>` manually).
  2. For private repos, configure git credentials (SSH key, credential helper, or token) so the clone can authenticate.
  3. Check network/proxy connectivity, then retry; if the repo lacks a catalog file, point at the right path or re-add with a corrected source.

Example fix

// before: unreachable private repo
await manager.addMarketplace("github:myorg/private-market");
// after: credentials configured, then retry
// git config credential.helper store / ssh key added
await manager.addMarketplace("github:myorg/private-market");
Defensive patterns

Strategy: try-catch

Validate before calling

const probe = Bun.spawnSync(["git", "ls-remote", gitUrl], { stdout: "pipe", stderr: "pipe" });
if (probe.exitCode !== 0) throw new Error(`Cannot access repository ${gitUrl}: ${probe.stderr.toString()}`);

Try / catch

try {
  const { catalog, clonePath } = await fetchMarketplace(gitSource, cacheDir);
} catch (err) {
  const msg = (err as Error).message;
  if (msg.startsWith("Cloned repository")) {
    // inspect cause: clone auth failure vs missing/invalid catalog
    console.error(msg); // includes original error text and source
  } else throw err;
}

Prevention

When it happens

Trigger: fetchMarketplace called with a git source where `git clone` fails (bad URL, no network, auth required), or the clone succeeds but readMarketplaceCatalog/parseMarketplaceCatalog fail (no catalog file, invalid JSON, wrong shape).

Common situations: Private repository without SSH keys or credentials configured; nonexistent repo or typo in the git URL; offline machine; firewall blocking git over HTTPS; upstream repo restructured and removed the catalog.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/af216be64f1d233e. Report an issue: GitHub.