Skip to content

pi update fails with "Could not determine latest pi version" when PI_SKIP_VERSION_CHECK is set #6549

Description

@fpl9000

What happened?

Command pi update outputs Error: Could not determine latest pi version when environment variable PI_SKIP_VERSION_CHECK is set.

Steps to reproduce

Steps to Reproduce

  1. Export the skip-check variable:
    export PI_SKIP_VERSION_CHECK=1
  2. Run:
    pi update
  3. Observe the error:
    Error: Could not determine latest pi version.
    

Expected behavior

Pi should update instead of outputing an error.

Root Cause

The user intent behind PI_SKIP_VERSION_CHECK is to suppress the passive startup version nag. However, the same variable is honored inside the low-level fetch helper, so it also short-circuits the explicit, user-initiated pi update command.

dist/utils/version-check.js

getLatestPiRelease() returns undefined immediately when the variable is set, before any network request is made:

export async function getLatestPiRelease(currentVersion, options = {}) {
    if (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE)
        return undefined;
    const response = await fetch(LATEST_VERSION_URL, { /* ... */ });
    // ...
}

dist/package-manager-cli.js

getSelfUpdatePlan() then treats that undefined as a hard failure:

async function getSelfUpdatePlan(force) {
    let latestRelease;
    try {
        latestRelease = await getLatestPiRelease(VERSION);
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        throw new Error(`Could not determine latest ${APP_NAME} version: ${message}`);
    }
    if (!latestRelease) {
        throw new Error(`Could not determine latest ${APP_NAME} version.`);
    }
    // ...
}

Because the early return undefined produces no thrown error, execution reaches the if (!latestRelease) branch, which throws the message with no trailing detail — exactly the text the user sees. (A network/HTTP failure would instead produce the variant with a trailing : <message>.)

PI_OFFLINE has the same effect and is arguably correct for an offline mode, but PI_SKIP_VERSION_CHECK conflating "don't nag me at startup" with "don't ever check, even when I explicitly ask" is the surprising part.

Impact

Any user who sets PI_SKIP_VERSION_CHECK (a common way to quiet the startup notification) cannot use pi update at all. The error message gives no hint that an environment variable is responsible, making it hard to diagnose.

Proposed Fix

Separate the passive version check (startup nag) from the active update path. The explicit pi update command should ignore PI_SKIP_VERSION_CHECK.

Option A (preferred): add an opt-in bypass and use it from the updater

In utils/version-check.js, allow callers to force the check regardless of the skip flag:

export async function getLatestPiRelease(currentVersion, options = {}) {
    const skip = process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE;
    if (skip && !options.force)
        return undefined;
    const response = await fetch(LATEST_VERSION_URL, {
        headers: {
            "User-Agent": getPiUserAgent(currentVersion),
            accept: "application/json",
        },
        signal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),
    });
    // ... unchanged ...
}

Then, in package-manager-cli.js, the explicit update path passes force: true:

async function getSelfUpdatePlan(force) {
    let latestRelease;
    try {
        latestRelease = await getLatestPiRelease(VERSION, { force: true });
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        throw new Error(`Could not determine latest ${APP_NAME} version: ${message}`);
    }
    if (!latestRelease) {
        throw new Error(`Could not determine latest ${APP_NAME} version.`);
    }
    // ...
}

The passive startup check (checkForNewPiVersion) continues to honor PI_SKIP_VERSION_CHECK by not passing force, so the startup nag stays suppressed as intended.

Note: PI_OFFLINE could reasonably continue to short-circuit even the forced path, since there is genuinely no network. If so, split the condition:

    if (process.env.PI_OFFLINE)
        return undefined;
    if (process.env.PI_SKIP_VERSION_CHECK && !options.force)
        return undefined;

Option B (minimal): improve the diagnostic

If the current behavior is intentional, at least make the error actionable when the variable is the cause:

    if (!latestRelease) {
        if (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE) {
            throw new Error(
                `Could not determine latest ${APP_NAME} version because ` +
                `PI_SKIP_VERSION_CHECK or PI_OFFLINE is set. Unset it and retry.`);
        }
        throw new Error(`Could not determine latest ${APP_NAME} version.`);
    }

Option A is recommended because it makes pi update do what the user explicitly asked, regardless of the passive-notification preference.

Version

0.80.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinguntriagedThis issue has been auto closed and has not been triaged

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions