{"record":{"id":"451241ce93350d52","repo":"can1357/oh-my-pi","slug":"invalid-pattern-err","errorCode":null,"errorMessage":"Invalid pattern: {err}","messagePattern":"Invalid pattern: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/pi-ast/src/ops.rs","lineNumber":106,"sourceCode":"\n#[must_use]\npub fn is_supported_file(file_path: &Path, explicit_lang: Option<&str>) -> bool {\n\tif explicit_lang.is_some() {\n\t\treturn true;\n\t}\n\tresolve_language(None, file_path).is_ok()\n}\n\npub fn compile_pattern(\n\tpattern: &str,\n\tselector: Option<&str>,\n\tstrictness: &MatchStrictness,\n\tlang: SupportLang,\n) -> Result<Pattern> {\n\tlet selector = selector.map(str::trim).filter(|s| !s.is_empty());\n\tlet mut compiled = if let Some(selector) = selector {\n\t\tPattern::contextual(pattern, selector, lang)\n\t\t\t.map_err(|err| anyhow!(\"Invalid pattern: {err}\"))?\n\t} else {\n\t\tmatch Pattern::try_new(pattern, lang) {\n\t\t\tOk(compiled) => compiled,\n\t\t\t// A fragment like `\"key\": $V` parses to multiple root nodes and is\n\t\t\t// rejected as `MultipleNode`; auto-wrap it in a single-node context\n\t\t\t// before giving up. Any other error, or a failed fallback, keeps the\n\t\t\t// original message so genuinely-bad patterns behave as before.\n\t\t\tErr(err @ PatternError::MultipleNode(_)) => {\n\t\t\t\tmatch compile_wrapped_fallback(pattern, strictness, lang) {\n\t\t\t\t\tSome(compiled) => return Ok(compiled),\n\t\t\t\t\tNone => return Err(anyhow!(\"Invalid pattern: {err}\")),\n\t\t\t\t}\n\t\t\t},\n\t\t\tErr(err) => return Err(anyhow!(\"Invalid pattern: {err}\")),\n\t\t}\n\t};\n\tcompiled.strictness = strictness.clone();\n\tOk(compiled)","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-ast/src/ops.rs#L88-L124","documentation":"Phase seeds in set_todos() must supply 'tasks' as a proper sequence (list/tuple). If 'tasks' is missing, not a Sequence, or is a str/bytes (deliberately excluded because a string is iterable but not a task list), RpcError is raised.","triggerScenarios":"Passing a phase dict without 'tasks', with tasks set to a plain string like \"fix bugs\", a dict, an int, or bytes instead of a list of task seeds.","commonSituations":"JSON configs where tasks was accidentally a comma-separated string, single task passed without a wrapping list, or a deserialized payload where tasks became a dict keyed by id.","solutions":["Wrap tasks in a list: [{\"title\": ...}, ...] — a bare string or dict is rejected.","Split string-encoded task lists into actual list items before calling set_todos().","Convert dict-shaped task collections (e.g. {id: task}) into list(task.values()).","Omit 'tasks' (defaults to ()) only if the library treats a missing key as empty; explicit None also coerces to ()."],"exampleFix":"// before\nclient.set_todos([{\"name\": \"Setup\", \"tasks\": \"fix bugs\"}])\n// after\nclient.set_todos([{\"name\": \"Setup\", \"tasks\": [{\"title\": \"fix bugs\"}]}])","handlingStrategy":"validation","validationCode":"tasks = seed.get(\"tasks\")\nif tasks is not None and (not isinstance(tasks, (list, tuple)) or isinstance(tasks, (str, bytes))):\n    raise ValueError(f\"phase 'tasks' must be a list, got {type(tasks).__name__}\")","typeGuard":"def is_task_sequence(v: object) -> TypeGuard[Sequence[object]]:\n    return isinstance(v, Sequence) and not isinstance(v, (str, bytes))","tryCatchPattern":"try:\n    client.set_todos(seeds)\nexcept RpcError as exc:\n    if \"must be a sequence\" in str(exc):\n        raise ValueError(f\"bad phase tasks: {exc}\") from exc\n    raise","preventionTips":["Always pass tasks as a list literal, even for a single task.","Reject strings at your config-loading boundary — a comma-separated tasks string is a common culprit.","Convert dict-keyed task collections to lists before sending."],"tags":["validation","rpc","todos","type-error"],"backgroundTag":"invalid-argument-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}