- Skill ID
- github/awesome-copilot/flowstudio-power-automate-debug
- Publisher
- github
- Repository
- awesome-copilot
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
github/awesome-copilot/flowstudio-power-automate-debugInstalls these files- SKILL.md
- references/common-errors.md
- references/debug-workflow.md
What this skill tells the agent
Power Automate Debugging with FlowStudio MCP
A step-by-step diagnostic process for investigating failing Power Automate cloud flows through the FlowStudio MCP server.
Real debugging examples: Expression error in child flow | Data entry, not a flow bug | Null value crashes child flow
Prerequisite: A FlowStudio MCP server must be reachable with a valid JWT. See the flowstudio-power-automate-mcp skill for connection setup. Subscribe at https://mcp.flowstudio.app
Source of Truth
Always call `list_skills` / `tool_search` first to confirm available tool names and parameter schemas. Tool names and parameters may change between server versions. This skill covers response shapes, behavioral notes, and diagnostic patterns — things tool schemas cannot tell you. If this document disagrees with tool_search or a real API response, the API wins.Python Helper
import json, urllib.request
MCP_URL = "https://mcp.flowstudio.app/mcp"
MCP_TOKEN = "<YOUR_JWT_TOKEN>"
def mcp(tool, **kwargs):
payload = json.dumps({"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {"name": tool, "arguments": kwargs}}).encode()
req = urllib.request.Request(MCP_URL, data=payload,
headers={"x-api-key": MCP_TOKEN, "Content-Type": "application/json",
"User-Agent": "FlowStudio-MCP/1.0"})
try:
resp = urllib.request.urlopen(req, timeout=120)
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", errors="replace")
raise RuntimeError(f"MCP HTTP {e.code}: {body[:200]}") from e
raw = json.loads(resp.read())
if "error" in raw:
raise RuntimeError(f"MCP error: {json.dumps(raw['error'])}")
return json.loads(raw["result"]["content"][0]["text"])
ENV = "<environment-id>" # e.g. Default-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxStep 1 — Locate the Flow
result = mcp("list_live_flows", environmentName=ENV)
# Returns a wrapper object: {mode, flows, totalCount, error}
target = next(f for f in result["flows"] if "My Flow Name" in f["displayName"])
FLOW_ID = target["id"] # plain UUID — use directly as flowName
print(FLOW_ID)Step 2 — Find the Failing Run
runs = mcp("get_live_flow_runs", environmentName=ENV, flowName=FLOW_ID, top=5)
# Returns direct array (newest first):
# [{"name": "08584296068667933411438594643CU15",
# "status": "Failed",
# "startTime": "2026-02-25T06:13:38.6910688Z",
# "endTime": "2026-02-25T06:15:24.1995008Z",
# "triggerName": "manual",
# "error": {"code": "ActionFailed", "message": "An action failed..."}},
# {"name": "...", "status": "Succeeded", "error": null, ...}]
for r in runs:
print(r["name"], r["status"], r["startTime"])
RUN_ID = next(r["name"] for r in runs if r["status"] == "Failed")Step 3 — Get the Top-Level Error
CRITICAL:get_live_flow_run_errortells you which action failed.get_live_flow_run_action_outputstells you why. You must call BOTH. Never stop at the error alone — error codes likeActionFailed,NotSpecified, andInternalServerErrorare generic wrappers. The actual root cause (wrong field, null value, HTTP 500 body, stack trace) is only visible in the action's inputs and outputs.
err = mcp("get_live_flow_run_error",
environmentName=ENV, flowName=FLOW_ID, runName=RUN_ID)
# Returns:
# {
# "runName": "08584296068667933411438594643CU15",
# "failedActions": [
# {"actionName": "Apply_to_each_prepare_workers", "status": "Failed",
# "error": {"code": "ActionFailed", "message": "An action failed..."},
# "startTime": "...", "endTime": "..."},
# {"actionName": "HTTP_find_AD_User_by_Name", "status": "Failed",
# "code": "NotSpecified", "startTime": "...", "endTime": "..."}
# ],
# "allActions": [
# {"actionName": "Apply_to_each", "status": "Skipped"},
# {"actionName": "Compose_WeekEnd", "status": "Succeeded"},
# ...
# ]
# }
# failedActions is ordered outer-to-inner. The ROOT cause is the LAST entry:
root = err["failedActions"][-1]
print(f"Root action: {root['actionName']} → code: {root.get('code')}")
# allActions shows every action's status — useful for spotting what was Skipped
# See common-errors.md to decode the error code.Step 4 — Inspect the Failing Action's Inputs and Outputs
This is the most important step. get_live_flow_run_error only gives you a generic error code. The actual error detail — HTTP status codes, response bodies, stack traces, null values — lives in the action's runtime inputs and outputs. Always inspect the failing action immediately after identifying it.# Get the root failing action's full inputs and outputs
root_action = err["failedActions"][-1]["actionName"]
detail = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=root_action)
if len(detail) > 1:
print(f"{root_action} returned {len(detail)} repetitions; inspect iteration indexes")
out = detail[0] if detail else {}
print(f"Action: {out.get('actionName')}")
print(f"Status: {out.get('status')}")
# For HTTP actions, the real error is in outputs.body
if isinstance(out.get("outputs"), dict):
status_code = out["outputs"].get("statusCode")
body = out["outputs"].get("body", {})
print(f"HTTP {status_code}")
print(json.dumps(body, indent=2)[:500])
# Error bodies are often nested JSON strings — parse them
if isinstance(body, dict) and "error" in body:
err_detail = body["error"]
if isinstance(err_detail, str):
err_detail = json.loads(err_detail)
print(f"Error: {err_detail.get('message', err_detail)}")
# For expression errors, the error is in the error field
if out.get("error"):
print(f"Error: {out['error']}")
# Also check inputs — they show what expression/URL/body was used
if out.get("inputs"):
print(f"Inputs: {json.dumps(out['inputs'], indent=2)[:500]}")What the action outputs reveal (that error codes don't)
Error code from get_live_flow_run_error | What get_live_flow_run_action_outputs reveals |
|---|---|
ActionFailed | Which nested action actually failed and its HTTP response |
NotSpecified | The HTTP status code + response body with the real error |
InternalServerError | The server's error message, stack trace, or API error JSON |
InvalidTemplate | The exact expression that failed and the null/wrong-type value |
BadRequest | The request body that was sent and why the server rejected it |
Foreach iterations
When actionName refers to an action inside a foreach, the output tool can return every repetition of that action. Each item may include repetitionIndexes with the loop name and zero-based itemIndex. Use iterationIndex to inspect one iteration after you find the suspicious item:
all_reps = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=root_action)
for rep in all_reps[:10]:
print(rep.get("repetitionIndexes"), rep.get("status"), rep.get("error"))
one_rep = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=root_action,
iterationIndex=3)Evidence Compose Bookends
For uncertain connector work, add a Compose_*_Request before the risky action and a Compose_*_Result after it, with the result action allowed on both Succeeded and Failed. This gives future debugging a clean payload snapshot
More from github
Use this skill in a project
Open any RiverX project, search the Skills panel for github/awesome-copilot/flowstudio-power-automate-debug, and install it in one click.
