can1357/oh-my-pi · error
Invalid ${scheme}:// list state '${stateRaw}'. Expected one
Error message
Invalid ${scheme}:// list state '${stateRaw}'. Expected one of: ${allowedStates.join(", ")}. What it means
parseListOptions validates the ?state= query parameter for issue:// and pr:// list URLs. PRs accept open|closed|merged|all; issues accept open|closed|all. An unknown value throws instead of silently falling back to 'open', because the fallback would be indistinguishable from 'no matches'.
Source
Thrown at packages/coding-agent/src/internal-urls/issue-pr-protocol.ts:83
limit: number;
author: string | undefined;
label: string | undefined;
}
type Parsed = ParsedSingle | ParsedList | ParsedPrDiff;
const LIST_LIMIT_DEFAULT = 30;
const LIST_LIMIT_MAX = 100;
function parseListOptions(url: InternalUrl, scheme: Scheme, repo: string | undefined): ParsedList {
const stateRaw = url.searchParams.get("state");
const allowedStates: ParsedList["state"][] =
scheme === "pr" ? ["open", "closed", "merged", "all"] : ["open", "closed", "all"];
if (stateRaw !== null && !(allowedStates as string[]).includes(stateRaw)) {
// Reject instead of silently falling back to "open": a typo'd state
// would otherwise return the open list, indistinguishable from "no
// matches for the requested state".
throw new Error(`Invalid ${scheme}:// list state '${stateRaw}'. Expected one of: ${allowedStates.join(", ")}.`);
}
const state = (stateRaw ?? "open") as ParsedList["state"];
const limitRaw = url.searchParams.get("limit");
let limit = LIST_LIMIT_DEFAULT;
if (limitRaw !== null) {
const parsed = parsePositiveDecimalInt(limitRaw);
if (parsed === undefined) {
throw new Error(
`Invalid ${scheme}:// list limit '${limitRaw}'. Expected a positive integer (max ${LIST_LIMIT_MAX}).`,
);
}
limit = Math.min(parsed, LIST_LIMIT_MAX);
}
return {
kind: "list",
repo,
state,View on GitHub (pinned to 9690622007)
Solutions
- Use a lowercase allowed value: open, closed, merged, all for pr://; open, closed, all for issue://
- Drop ?state= entirely to get the 'open' default explicitly
- Fix casing in generated URLs (state is compared case-sensitively)
Example fix
// before
resolve('pr://org/repo?state=Merged')
// after
resolve('pr://org/repo?state=merged') Defensive patterns
Strategy: validation
Validate before calling
const PR_STATES = ['open','closed','merged','all']
const ISSUE_STATES = ['open','closed','all']
const allowed = scheme === 'pr' ? PR_STATES : ISSUE_STATES
if (state !== undefined && !allowed.includes(state)) throw new Error(`bad ${scheme} state: ${state}`) Type guard
const isPrState = (s: string): s is 'open'|'closed'|'merged'|'all' => ['open','closed','merged','all'].includes(s)
Prevention
- Always lowercase state values in generated URLs
- Use a typed union for state instead of raw strings
- Remember 'merged' is pr-only
When it happens
Trigger: Calling pr://...?state=Merged (case-sensitive) or issue://...?state=merged (invalid for issues) via parseUrl.
Common situations: Case mistakes ('Open' vs 'open'); using the PR-only 'merged' state on issue://; typos like 'closes'.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid GitHub release metadata
- Invalid ${scheme}:// list limit '${limitRaw}'. Expected a po
- ${label} must not be empty
- run URL repository does not match the provided repo
- GITHUB_TOKEN and ROBOMP_GH_PROXY_URL are mutually exclusive
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/06643ca1d9928796.
Report an issue: GitHub.