can1357/oh-my-pi · error · Error
Malformed npm registry response for ${pkg}: missing version
Error message
Malformed npm registry response for ${pkg}: missing version What it means
Thrown when the npm registry responds 200 but the JSON body is not an object containing a string `version` field. The updater validates the parsed manifest shape before trusting it, since downstream logic (comparison, download URLs) depends on `version`.
Source
Thrown at packages/coding-agent/src/cli/update-cli.ts:789
} catch (err) {
if (isTimeoutError(err)) {
throw new Error(`Timed out fetching release info for ${pkg} after ${Math.round(timeoutMs / 1000)}s`, {
cause: err,
});
}
if (isUnsupportedProxyError(err)) throw new Error(unsupportedProxyMessage(), { cause: err });
throw err;
}
if (!response.ok) {
if (response.status === 404 && channel === "canary") {
throw new Error(`No canary release has been published for ${pkg} yet. Try \`${APP_NAME} update --stable\`.`);
}
throw new Error(`Failed to fetch release info for ${pkg}: ${response.statusText}`);
}
const data: unknown = await response.json();
if (!isRecord(data) || typeof data.version !== "string") {
throw new Error(`Malformed npm registry response for ${pkg}: missing version`);
}
return { version: data.version, manifest: data };
}
/**
* Get the latest release info from the npm registry, following `omp.rename`
* pointers ({@link resolveReleaseRename}) when the package has moved to a new
* npm name. Version, dist, and install names all come from the final manifest
* in the chain. Uses npm instead of GitHub API to avoid unauthenticated rate
* limiting.
*/
export async function getLatestRelease(
options: { timeoutMs?: number; channel?: UpdateChannel } = {},
): Promise<ReleaseInfo> {
const timeoutMs = options.timeoutMs ?? RELEASE_METADATA_TIMEOUT_MS;
const channel = options.channel ?? "stable";
const packages: ReleasePackages = { ...CURRENT_PACKAGES };
const visited = new Set([packages.pkg]);View on GitHub (pinned to 9690622007)
Solutions
- Check which registry is being used (echo $NPM_REGISTRY / npm config get registry) and reset to the official one
- Disconnect from captive-portal Wi-Fi or complete portal login, then retry
- curl the endpoint and inspect the JSON: curl -s https://registry.npmjs.org/<pkg>/latest
- Bypass TLS-intercepting proxies or install their CA so the real registry response arrives
Example fix
// before: custom mirror returns {error: 'not found'}
export NPM_REGISTRY=https://internal-mirror.example/
omp update
// after: use the official registry
unset NPM_REGISTRY
omp update Defensive patterns
Strategy: validation
Validate before calling
const res = await fetch(`${registry}/<pkg>/latest`);
const data = await res.json();
if (typeof data?.version !== "string") throw new Error("registry returned non-release payload; check registry/proxy config"); Type guard
function isRegistryManifest(v: unknown): v is { version: string; [k: string]: unknown } {
return typeof v === "object" && v !== null && typeof (v as { version?: unknown }).version === "string";
} Try / catch
try {
await runUpdate();
} catch (err) {
if (String(err?.message).includes("Malformed npm registry response")) {
console.error("A proxy/captive portal likely replaced the response. Check registry config and network.");
return;
}
throw err;
} Prevention
- Point NPM_CONFIG_REGISTRY / npm registry at the official registry for updates
- Complete captive-portal login before running updates
- Bypass or correctly configure TLS-intercepting proxies
- Sanity-check the endpoint with curl before scripted updates
When it happens
Trigger: response.json() returns null, an array, or an object without a string version property — e.g. a captive portal/proxy returned an HTML login page with status 200, or a registry mirror returned an error envelope.
Common situations: Corporate proxies or Wi-Fi captive portals intercepting HTTPS with a 200 HTML page (less common but seen with TLS-intercepting appliances), misconfigured custom registry (npm_config_registry pointing at a non-registry endpoint), corrupted mirror.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Token response missing required fields
- Timed out fetching release info for ${pkg} after ${Math.roun
- Failed to fetch release info for ${pkg}: ${response.statusTe
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6e87efd0047c6c91.
Report an issue: GitHub.