Relationships
#2536 command/shell: a non-zero exit drops stdout/stderr from the --json result, the result and log data artifacts, and the method-summary report
Opened by matthewbonig · 9/25/2026
Summary
When a command/shell execute exits non-zero, the command's captured stdout
and stderr become unreachable to any consumer that reads the run's structured
result. The --json failure payload carries only the error string, neither the
result resource nor the log file data artifact is written, and
@swamp/method-summary records only the exit code.
The output is not lost from disk — it is written to
.swamp/outputs/command/shell/execute/<modelId>-<timestamp>.log — but nothing
in the failure path points at that file. On success the --json payload
includes a logFile field; on failure it does not.
The practical effect is that a failing shell step is undiagnosable from its own
output. In this repo that cost five consecutive pre-pr-verify runs, each of which
reported only its exit code. The output was recovered only by re-running the
identical command with ignoreExitCode=true.
Reproduction
Identical command, run twice against the same command/shell model, differing
only in ignoreExitCode.
Failing (default):
swamp model method run exman-shell execute \
--input run='echo "MARKER-STDOUT-LINE"; echo "MARKER-STDERR-LINE" >&2; exit 3' \
--json{
"error": "Command exited with code 3",
"code": "method_execution_failed"
}That is the entire payload. No stdout, no stderr, no exitCode, no
logFile, no dataArtifacts.
Same command with --input ignoreExitCode=true:
{
"status": "succeeded",
"logFile": ".../.swamp/outputs/command/shell/execute/5bd6f0fc-...-2026-09-25T16-09-22-626Z.log",
"dataArtifacts": [
{
"name": "result",
"attributes": {
"exitCode": 3,
"command": "echo \"MARKER-STDOUT-LINE\"; echo \"MARKER-STDERR-LINE\" >&2; exit 3",
"durationMs": 5,
"stdout": "MARKER-STDOUT-LINE",
"stderr": "MARKER-STDERR-LINE"
}
},
{ "name": "log" }
]
}The process ran identically in both cases — same exitCode: 3, same output.
Only the reporting differs.
Three separate consumers lose the output
1. The --json payload. Shown above. This is the path agents and CI use.
In human (non---json) mode the output does stream to the terminal:
Executing execute · 16:12:03 UTC
MARKER-STDOUT-LINE
MARKER-STDERR-LINE
Error: Command exited with code 3So this is specifically a structured-output defect, not a capture defect.
2. The result and log data artifacts are never written. After the
failing run, swamp data list exman-shell shows only the report artifacts.
After the ignoreExitCode run it shows result v1 and log v1. A second
failing run afterwards left both at v1 — the failure path writes neither.
Both are declared on the type (swamp model type describe command/shell):
result carries stdout/stderr/exitCode, and log is a streaming: true
text/plain file resource. Because neither is written, swamp data query and
data.latest(<name>, 'result') cannot reach a failed step's output after the
fact. Post-hoc diagnosis of a past failure is not possible at all — only
re-running is.
3. @swamp/method-summary records only the exit code. This is the documented
place to look after a failure — the swamp skill's troubleshooting guidance and
this repo's conventions both say reports run even on failure and capture
structured diagnostics. Here it captures nothing usable:
{
"status": "failed",
"error": "Command exited with code 3",
"narrative": "execute on exman-shell (command/shell) failed: Command exited with code 3",
"methodArgs": ["run"]
}The markdown rendering has an ## Error section containing the same one line.
The report enumerates the result spec under outputSpecs, including its
stdout and stderr properties, while carrying no value for either.
Expected behaviour
A non-zero exit is an ordinary, expected outcome for a shell command — it is the outcome you most need the output for. At minimum the failure should be diagnosable without re-running:
- the
--jsonfailure payload should carryexitCode,stdout,stderrand thelogFilepath, or at least thelogFilepath; - the
resultandlogartifacts should be written before the method throws, so the output survives in queryable data; @swamp/method-summaryshould include the captured output for a failed shell method, since diagnosing failures is what the report is for.
Current workaround and why it is inadequate
Re-run with ignoreExitCode=true. This requires that the failure be
reproducible, and it inverts the method's success semantics — the step then
reports success on any exit code, so it cannot be left in place for a
verification step whose whole purpose is to fail the run. It is a diagnostic
detour, not a fix.
Observed on
- swamp
20260830.034252.0-sha.43b19693 command/shelltype version2026.02.09.1- macOS 27.0 (Darwin 27.0.0), arm64
Closed
No activity in this phase yet.
stack72 commented 9/25/2026, 4:55:28 PM
Hey @matthewbonig thanks for the detailed reproduction. This was fixed in v20260922.204047.0-sha.4957bcbd by #2555 (fix(models): keep a failing shell step's output instead of discarding it). Failed command/shell executions now persist the result and log artifacts before raising the non-zero-exit error, and attach those artifacts to the failed run. This restores the failure JSON/run record, queryable artifacts, log path, and downstream method-summary diagnostics. The current latest release, v20260925.163149.0-sha.bea803c9, includes the fix. Please upgrade and reopen if you can reproduce it there.
Sign in to post a ripple.