stablyai/orca · error · RuntimeError
{action} is not a valid secondary action
Error message
{action} is not a valid secondary action What it means
Raised in the perform_secondary_action branch of run_operation (runtime.py:1091) when no accessibility action label on the target node case-insensitively equals operation['action'], or when the matching label's perform_action call returned False (the for/else ensures the raise runs only if no break occurred — i.e. no label both matched and executed successfully). The placeholder is operation.get('action','') verbatim.
Source
Thrown at native/computer-use-linux/runtime.py:1091
if not handled:
click_at(
*screen_point(bounds, saved, operation.get("x"), operation.get("y"), node),
operation.get("mouse_button", "left"),
click_count,
operation.get("modifiers"),
)
action = {"path": "synthetic", "actionName": None, "fallbackReason": "actionUnsupported"}
else:
labels = action_labels(node)
action = {"path": "accessibility", "actionName": labels[preferred] if preferred is not None and preferred < len(labels) else "action", "fallbackReason": None}
elif tool == "perform_secondary_action":
wanted = str(operation.get("action", "")).lower()
for index, label in enumerate(action_labels(node)):
if label.lower() == wanted and perform_action(node, index):
action = {"path": "accessibility", "actionName": label, "fallbackReason": None}
break
else:
raise RuntimeError(f'{operation.get("action", "")} is not a valid secondary action')
elif tool == "scroll":
# Why: pointer wheel events should land in the requested app window even
# when another desktop window is currently foregrounded.
restore_window(app, window)
scroll_at(*screen_point(bounds, saved, operation.get("x"), operation.get("y"), node), operation.get("direction"), operation.get("pages"))
action = {"path": "synthetic", "actionName": "scroll", "fallbackReason": None}
elif tool == "drag":
# Why: pointer drags are synthetic global input, so activate the target
# window before using cached coordinates from its accessibility tree.
restore_window(app, window)
drag_between(
screen_point(bounds, operation.get("fromElement"), operation.get("from_x"), operation.get("from_y"), from_node),
screen_point(bounds, operation.get("toElement"), operation.get("to_x"), operation.get("to_y"), to_node),
)
action = {"path": "synthetic", "actionName": "drag", "fallbackReason": None}
elif tool == "type_text":
type_text(require_non_empty_string(operation.get("text"), "text"))
action = {"path": "synthetic", "actionName": "typeText", "fallbackReason": None, "verification": {"state": "unverified", "reason": "synthetic_input"}}View on GitHub (pinned to 1136503c6a)
Solutions
- Call get_app_state first and read the element's available action labels, then send one of those exact labels.
- Strip whitespace from operation['action'] before sending.
- Fall back to 'click' (the primary action) if the desired secondary action is unavailable.
Example fix
// before
{"tool":"perform_secondary_action","action":"toggle"} // node has no 'toggle'
// after: use a label listed by get_app_state
{"tool":"perform_secondary_action","action":"press"} Defensive patterns
Strategy: validation
Validate before calling
state = run_operation({"tool": "get_app_state", "app": app})
labels = {a.lower() for a in element_action_labels(state, element_index)}
wanted = str(raw_action).strip().lower()
if wanted not in labels:
raise ValueError(f"action {wanted!r} not in {sorted(labels)}")
op = {"tool": "perform_secondary_action", "action": wanted} Type guard
def is_known_action(state, element_index, action) -> bool:
labels = {a.lower() for a in element_action_labels(state, element_index)}
return str(action).strip().lower() in labels Try / catch
try:
run_operation(op)
except RuntimeError as e:
if "is not a valid secondary action" in str(e):
op = {"tool": "click", "element": element_index} # fallback
run_operation(op)
else:
raise Prevention
- Always call get_app_state and read the element's action labels before issuing perform_secondary_action.
- Strip whitespace from the action name before sending.
- Fall back to the primary click action when the desired secondary action is absent.
When it happens
Trigger: Calling the 'perform_secondary_action' tool with operation['action'] set to a label not exposed by the element (e.g. 'toggle' on a node that only exposes 'click','press'); or a label that matches but perform_action fails (do_action returns falsy), leaving the loop without a break.
Common situations: An agent guesses an action name without first reading get-app-state's action list for the element; UI changed and a previously valid action label disappeared; case mismatch (handled, but trailing whitespace is not stripped).
Related errors
- element value is not settable
- {name} must be a positive number
- {name} is required
- unsupported mouse button: {button}
- click modifiers require modifier keys only
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/ff6d9f96e0b57efb.
Report an issue: GitHub.