larksuite/cli · error

expected version %s, got %q

Error message

expected version %s, got %q

What it means

VerifyBinary compares the actual version reported by the new binary (last whitespace-separated field, with a leading "v" trimmed) against the expected version it downloaded, and throws "expected version %s, got %q" on mismatch. This prevents installing a binary that is not the release the updater intended, e.g. a stale or mislabeled artifact.

Source

Thrown at internal/selfupdate/updater.go:461

		}
	}
	ctx, cancel := context.WithTimeout(context.Background(), verifyTimeout)
	defer cancel()
	out, err := exec.CommandContext(ctx, exe, "--version").Output()
	if ctx.Err() == context.DeadlineExceeded {
		return fmt.Errorf("binary verification timed out after %s", verifyTimeout)
	}
	if err != nil {
		return fmt.Errorf("binary not executable: %w", err)
	}
	fields := strings.Fields(strings.TrimSpace(string(out)))
	if len(fields) == 0 {
		return fmt.Errorf("empty version output")
	}
	actual := strings.TrimPrefix(fields[len(fields)-1], "v")
	expected := strings.TrimPrefix(expectedVersion, "v")
	if actual != expected {
		return fmt.Errorf("expected version %s, got %q", expectedVersion, actual)
	}
	return nil
}

// Truncate returns the last maxLen runes of s.
func Truncate(s string, maxLen int) string {
	if maxLen <= 0 {
		return ""
	}
	r := []rune(s)
	if len(r) <= maxLen {
		return s
	}
	return string(r[len(r)-maxLen:])
}

// resolveExe returns the resolved path of the current running binary.
func (u *Updater) resolveExe() (string, error) {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Compare the actual --version output with the release tag; re-download or re-publish the correct asset
  2. Purge CDN/proxy caches serving the old artifact
  3. Make the binary's last --version field exactly the version (optionally "v"-prefixed); fix the version stamping in the build
  4. Ensure the updater passes the same expectedVersion string form that the binary prints

Example fix

// before (binary prints build info last)
fmt.Printf("v%s (%s)\n", version, commit) // last field is commit -> mismatch
// after
fmt.Printf("v%s\n", version) // last field is the version
Defensive patterns

Strategy: validation

Validate before calling

out, _ := exec.Command(binPath, "--version").Output()
fields := strings.Fields(strings.TrimSpace(string(out)))
if len(fields) == 0 { return fmt.Errorf("no version output") }
actual := strings.TrimPrefix(fields[len(fields)-1], "v")
expected := strings.TrimPrefix(expectedVersion, "v")
if actual != expected { return fmt.Errorf("stale artifact: want %s got %s", expected, actual) }

Try / catch

if err := update.VerifyBinary(ctx, path, expectedVersion); err != nil {
    var mismatch = err.Error()
    if strings.HasPrefix(mismatch, "expected version") {
        // purge cache and retry download once with the pinned asset URL
        return retryWithFreshDownload()
    }
    return err
}

Prevention

When it happens

Trigger: The binary runs and prints a version, but after TrimPrefix("v") the last field of --version output does not equal the expectedVersion string passed to VerifyBinary.

Common situations: Release tag updated but the asset still points at an old build; CDN/cache serving a stale artifact; version string format changed (e.g. "1.2.3 (abc123)" where the last field is a commit hash, not the version); expected version passed with inconsistent "v" prefix handling.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/0f68593cbf7fe2a8. Report an issue: GitHub.