can1357/oh-my-pi · error · anyhow::Error
Unable to infer language from file extension: {}. Specify `l
Error message
Unable to infer language from file extension: {}. Specify `lang` explicitly. What it means
When a set_todos() seed is a dict (phase seed), the client requires a 'name' key holding a non-empty, non-whitespace string. A missing, empty, or whitespace-only name means the phase cannot be identified or displayed, so RpcError is raised during normalization before sending.
Source
Thrown at crates/pi-ast/src/ops.rs:82
}
#[must_use]
pub fn supported_lang_list() -> String {
SupportLang::sorted_aliases().join(", ")
}
pub fn resolve_supported_lang(value: &str) -> Result<SupportLang> {
SupportLang::from_alias(value).ok_or_else(|| {
anyhow!("Unsupported language '{value}'. Supported: {}", supported_lang_list())
})
}
pub fn resolve_language(lang: Option<&str>, file_path: &Path) -> Result<SupportLang> {
if let Some(lang) = lang.map(str::trim).filter(|lang| !lang.is_empty()) {
return resolve_supported_lang(lang);
}
SupportLang::from_path(file_path).ok_or_else(|| {
anyhow!(
"Unable to infer language from file extension: {}. Specify `lang` explicitly.",
file_path.display()
)
})
}
#[must_use]
pub fn is_supported_file(file_path: &Path, explicit_lang: Option<&str>) -> bool {
if explicit_lang.is_some() {
return true;
}
resolve_language(None, file_path).is_ok()
}
pub fn compile_pattern(
pattern: &str,
selector: Option<&str>,
strictness: &MatchStrictness,View on GitHub (pinned to 9690622007)
Solutions
- Add a non-empty 'name' string to every phase seed dict.
- Strip/validate names before calling set_todos(); drop or rename phases with empty names.
- If you meant flat todo items, pass plain item dicts instead of phase-shaped dicts (keys like 'name' make it look like a phase).
- Catch RpcError during normalization and report which phase index lacks a name.
Example fix
// before
client.set_todos([{"id": "p1", "tasks": [{"title": "do it"}]}])
// after
client.set_todos([{"id": "p1", "name": "Setup", "tasks": [{"title": "do it"}]}]) Defensive patterns
Strategy: validation
Validate before calling
for i, seed in enumerate(phases):
name = seed.get("name") if isinstance(seed, dict) else None
if not isinstance(name, str) or not name.strip():
raise ValueError(f"phase {i + 1} needs a non-empty 'name'") Type guard
def is_valid_phase_seed(seed: object) -> TypeGuard[dict]:
name = seed.get("name") if isinstance(seed, dict) else None
return isinstance(name, str) and bool(name.strip()) Try / catch
try:
client.set_todos(seeds)
except RpcError as exc:
if "non-empty 'name'" in str(exc):
raise ValueError(f"invalid phase in set_todos: {exc}") from exc
raise Prevention
- Build phases through a constructor/helper that requires name as a parameter.
- Strip and validate names when loading phases from JSON or a database.
- Keep flat items and phases in separate code paths so phase-shaped keys aren't accidentally dropped.
When it happens
Trigger: Passing a phase dict like {"tasks": [...]} with no 'name', or {"name": ""} or {"name": " "} to set_todos().
Common situations: Programmatically building phases where name was conditionally omitted, deserializing phases from JSON/DB where an empty name was stored, or confusing flat todo items (which don't need name) with phase seeds (which do).
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- Unsupported language '{value}'. Supported: {}
- Invalid pattern: {err}
- Unsupported todo status: {seed.status}
- Todo items must provide a non-empty 'content' value
- Host URI scheme must be a non-empty string
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/fff60052a8afae57.
Report an issue: GitHub.