workflow_run_trigger fires the workflow but silently drops all inputs. The triggered run starts with template literals unresolved — the job name shows literally Dispatch issue #${{ inputs.issue_number }} via ${{ inputs.harness }} instead of the substituted values.
The MCP tool also returns an error on every call:
{"code": -32000, "message": "missing Location header in dispatch response"}
Despite this error, the workflow does fire — but without inputs. This makes workflow_run_trigger unusable for any workflow that depends on workflow_dispatch inputs (which is the entire point of CAD dispatch).
Expected: workflow run #N starts with inputs.issue_number=36, inputs.harness=agentsquad etc resolved in job names and steps.
Actual: workflow fires (run created), but all ${{ inputs.* }} remain as literal template strings. The inputs object was not passed to Gitea.
Verified in two consecutive calls (runs #32 and #33 in mathias/agentsquad) — both show unresolved template literals and the same missing Location header error.
Root cause (hypothesis)
The Gitea API POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches returns HTTP 204 No Content on success — no Location header. The MCP tool likely expects a Location header to parse the new run ID, and when absent it both surfaces the error and fails to attach the request body (inputs) to the dispatch call.
Two possible failure modes:
The inputs JSON is not being serialised into the request body at all
The inputs are sent but the tool errors before confirming, and Gitea silently ignores a malformed body
Check the raw HTTP request body sent to Gitea — if inputs is absent or {}, that's the bug.
Impact
Blocks CAD dispatch from claude.ai. The entire value of workflow_run_trigger for the homelab is dispatching issue-specific agent runs with typed inputs. Without inputs landing, every dispatch is a no-op that fires the wrong workflow context.
Workaround: trigger manually from Gitea UI (Actions → cad-dispatch.yml → Run workflow).
Expected fix
Serialise inputs correctly into the POST body as {"ref": "...", "inputs": {...}}
Handle 204 No Content as success (no Location header expected for workflow dispatch)
Return the run ID by listing recent runs after dispatch (poll GET /repos/{owner}/{repo}/actions/runs?event=workflow_dispatch&limit=1) rather than parsing a Location header
Gitea API reference
POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches
Body: {"ref": "main", "inputs": {"key": "value"}}
Response: 204 No Content (success)
Acceptance criteria
workflow_run_trigger with non-empty inputs passes inputs to Gitea correctly
204 No Content response treated as success (no error returned to caller)
Triggered run resolves ${{ inputs.* }} correctly in Gitea Actions UI
Tool returns the new run ID (via post-dispatch listing or other means)
missing Location header error no longer surfaced on successful dispatch
Related
mathias/agentsquad runs #32 and #33 — both broken dispatches
mathias/agentsquad issue #36 — the intended dispatch target
## Problem
`workflow_run_trigger` fires the workflow but silently drops all `inputs`. The triggered run starts with template literals unresolved — the job name shows literally `Dispatch issue #${{ inputs.issue_number }} via ${{ inputs.harness }}` instead of the substituted values.
The MCP tool also returns an error on every call:
```
{"code": -32000, "message": "missing Location header in dispatch response"}
```
Despite this error, the workflow does fire — but without inputs. This makes `workflow_run_trigger` unusable for any workflow that depends on `workflow_dispatch` inputs (which is the entire point of CAD dispatch).
## Reproduction
```
gitea:workflow_run_trigger(
owner="mathias",
name="agentsquad",
workflow="cad-dispatch.yml",
ref="main",
inputs={"issue_number": "36", "repo": "mathias/agentsquad", "harness": "agentsquad", "tier": "heavy"}
)
```
**Expected:** workflow run #N starts with `inputs.issue_number=36`, `inputs.harness=agentsquad` etc resolved in job names and steps.
**Actual:** workflow fires (run created), but all `${{ inputs.* }}` remain as literal template strings. The `inputs` object was not passed to Gitea.
Verified in two consecutive calls (runs #32 and #33 in `mathias/agentsquad`) — both show unresolved template literals and the same `missing Location header` error.
## Root cause (hypothesis)
The Gitea API `POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches` returns HTTP 204 No Content on success — no `Location` header. The MCP tool likely expects a `Location` header to parse the new run ID, and when absent it both surfaces the error and fails to attach the request body (inputs) to the dispatch call.
Two possible failure modes:
1. The inputs JSON is not being serialised into the request body at all
2. The inputs are sent but the tool errors before confirming, and Gitea silently ignores a malformed body
Check the raw HTTP request body sent to Gitea — if `inputs` is absent or `{}`, that's the bug.
## Impact
**Blocks CAD dispatch from claude.ai.** The entire value of `workflow_run_trigger` for the homelab is dispatching issue-specific agent runs with typed inputs. Without inputs landing, every dispatch is a no-op that fires the wrong workflow context.
Workaround: trigger manually from Gitea UI (Actions → cad-dispatch.yml → Run workflow).
## Expected fix
1. Serialise `inputs` correctly into the POST body as `{"ref": "...", "inputs": {...}}`
2. Handle 204 No Content as success (no Location header expected for workflow dispatch)
3. Return the run ID by listing recent runs after dispatch (poll `GET /repos/{owner}/{repo}/actions/runs?event=workflow_dispatch&limit=1`) rather than parsing a Location header
## Gitea API reference
```
POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches
Body: {"ref": "main", "inputs": {"key": "value"}}
Response: 204 No Content (success)
```
## Acceptance criteria
- [ ] `workflow_run_trigger` with non-empty `inputs` passes inputs to Gitea correctly
- [ ] 204 No Content response treated as success (no error returned to caller)
- [ ] Triggered run resolves `${{ inputs.* }}` correctly in Gitea Actions UI
- [ ] Tool returns the new run ID (via post-dispatch listing or other means)
- [ ] `missing Location header` error no longer surfaced on successful dispatch
## Related
- `mathias/agentsquad` runs #32 and #33 — both broken dispatches
- `mathias/agentsquad` issue #36 — the intended dispatch target
- CAD dispatch workflow: `mathias/agentsquad/.gitea/workflows/cad-dispatch.yml`
Root cause confirmed: Gitea's dispatch endpoint returns 204 No Content with no Location header. DispatchWorkflow required that header, so every successful dispatch errored with missing Location header and never returned a run ID. The old tests baked in a fake Location header real Gitea never sends.
Note on the "dropped inputs" hypothesis: the request body already serialized {"ref":..., "inputs":{...}} correctly — inputs do reach Gitea. The unresolved ${{ inputs.* }} you saw in runs #32/#33 is almost certainly a downstream cad-dispatch.yml / workflow-YAML issue (cf. the unquoted on:-key → YAML-boolean → 0-jobs footgun), not this tool. Worth re-verifying now that dispatch returns a real run ID to inspect.
What changed:
DispatchWorkflow → error-only; 204 treated as success, no Location needed. ✅ AC: 204 = success, no error surfaced.
Run ID resolved via listing: snapshot newest event=workflow_dispatch run before dispatch (baseline), then poll ListWorkflowRuns after and return the newest run with ID above the baseline — avoids returning a stale prior run. ✅ AC: tool returns the new run ID.
If the run hasn't registered within the poll window (5×1s), returns dispatched:true + a note instead of failing — the workflow is firing regardless.
Inputs forwarding covered by test. ✅ AC.
task check passes (lint 0, tests green -race, govulncheck clean).
Remaining AC — "triggered run resolves ${{ inputs.* }} in the Actions UI" — is a live end-to-end check against real Gitea; the tool contract is now correct. Suggest a follow-up live dispatch to confirm, and if templates are still literal, it points at cad-dispatch.yml, not gitea-mcp.
Fixed in v0.3.1 (commit on `main`).
**Root cause confirmed:** Gitea's dispatch endpoint returns `204 No Content` with **no `Location` header**. `DispatchWorkflow` required that header, so every successful dispatch errored with `missing Location header` and never returned a run ID. The old tests baked in a fake `Location` header real Gitea never sends.
**Note on the "dropped inputs" hypothesis:** the request body already serialized `{"ref":..., "inputs":{...}}` correctly — inputs *do* reach Gitea. The unresolved `${{ inputs.* }}` you saw in runs #32/#33 is almost certainly a downstream `cad-dispatch.yml` / workflow-YAML issue (cf. the unquoted `on:`-key → YAML-boolean → 0-jobs footgun), not this tool. Worth re-verifying now that dispatch returns a real run ID to inspect.
**What changed:**
- `DispatchWorkflow` → error-only; **204 treated as success**, no `Location` needed. ✅ AC: 204 = success, no error surfaced.
- Run ID resolved via listing: snapshot newest `event=workflow_dispatch` run **before** dispatch (baseline), then poll `ListWorkflowRuns` after and return the newest run with ID above the baseline — avoids returning a stale prior run. ✅ AC: tool returns the new run ID.
- If the run hasn't registered within the poll window (5×1s), returns `dispatched:true` + a note instead of failing — the workflow is firing regardless.
- Inputs forwarding covered by test. ✅ AC.
`task check` passes (lint 0, tests green `-race`, govulncheck clean).
Remaining AC — "triggered run resolves `${{ inputs.* }}` in the Actions UI" — is a live end-to-end check against real Gitea; the tool contract is now correct. Suggest a follow-up live dispatch to confirm, and if templates are still literal, it points at `cad-dispatch.yml`, not gitea-mcp.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
workflow_run_triggerfires the workflow but silently drops allinputs. The triggered run starts with template literals unresolved — the job name shows literallyDispatch issue #${{ inputs.issue_number }} via ${{ inputs.harness }}instead of the substituted values.The MCP tool also returns an error on every call:
Despite this error, the workflow does fire — but without inputs. This makes
workflow_run_triggerunusable for any workflow that depends onworkflow_dispatchinputs (which is the entire point of CAD dispatch).Reproduction
Expected: workflow run #N starts with
inputs.issue_number=36,inputs.harness=agentsquadetc resolved in job names and steps.Actual: workflow fires (run created), but all
${{ inputs.* }}remain as literal template strings. Theinputsobject was not passed to Gitea.Verified in two consecutive calls (runs #32 and #33 in
mathias/agentsquad) — both show unresolved template literals and the samemissing Location headererror.Root cause (hypothesis)
The Gitea API
POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatchesreturns HTTP 204 No Content on success — noLocationheader. The MCP tool likely expects aLocationheader to parse the new run ID, and when absent it both surfaces the error and fails to attach the request body (inputs) to the dispatch call.Two possible failure modes:
Check the raw HTTP request body sent to Gitea — if
inputsis absent or{}, that's the bug.Impact
Blocks CAD dispatch from claude.ai. The entire value of
workflow_run_triggerfor the homelab is dispatching issue-specific agent runs with typed inputs. Without inputs landing, every dispatch is a no-op that fires the wrong workflow context.Workaround: trigger manually from Gitea UI (Actions → cad-dispatch.yml → Run workflow).
Expected fix
inputscorrectly into the POST body as{"ref": "...", "inputs": {...}}GET /repos/{owner}/{repo}/actions/runs?event=workflow_dispatch&limit=1) rather than parsing a Location headerGitea API reference
Acceptance criteria
workflow_run_triggerwith non-emptyinputspasses inputs to Gitea correctly${{ inputs.* }}correctly in Gitea Actions UImissing Location headererror no longer surfaced on successful dispatchRelated
mathias/agentsquadruns #32 and #33 — both broken dispatchesmathias/agentsquadissue #36 — the intended dispatch targetmathias/agentsquad/.gitea/workflows/cad-dispatch.ymlFixed in v0.3.1 (commit on
main).Root cause confirmed: Gitea's dispatch endpoint returns
204 No Contentwith noLocationheader.DispatchWorkflowrequired that header, so every successful dispatch errored withmissing Location headerand never returned a run ID. The old tests baked in a fakeLocationheader real Gitea never sends.Note on the "dropped inputs" hypothesis: the request body already serialized
{"ref":..., "inputs":{...}}correctly — inputs do reach Gitea. The unresolved${{ inputs.* }}you saw in runs #32/#33 is almost certainly a downstreamcad-dispatch.yml/ workflow-YAML issue (cf. the unquotedon:-key → YAML-boolean → 0-jobs footgun), not this tool. Worth re-verifying now that dispatch returns a real run ID to inspect.What changed:
DispatchWorkflow→ error-only; 204 treated as success, noLocationneeded. ✅ AC: 204 = success, no error surfaced.event=workflow_dispatchrun before dispatch (baseline), then pollListWorkflowRunsafter and return the newest run with ID above the baseline — avoids returning a stale prior run. ✅ AC: tool returns the new run ID.dispatched:true+ a note instead of failing — the workflow is firing regardless.task checkpasses (lint 0, tests green-race, govulncheck clean).Remaining AC — "triggered run resolves
${{ inputs.* }}in the Actions UI" — is a live end-to-end check against real Gitea; the tool contract is now correct. Suggest a follow-up live dispatch to confirm, and if templates are still literal, it points atcad-dispatch.yml, not gitea-mcp.