Relationships
#3006 vault read-secret: to a pipe or file, drops the last line of a multi-line value when that line is 1024+ chars with no trailing newline (exit 0)
Opened by randybias · 10/4/2026· Shipped 10/5/2026
Summary
swamp vault read-secret <vault> <key>, with stdout NOT a terminal (pipe or file), drops the LAST line of a multi-line value when that line is 1024 characters or longer and has no trailing newline. Exit status is 0, and nothing goes to stderr. The value is stored whole: --json and terminal output return all of it. A script that builds a file from the plain output (for example a kubeconfig, where client-key-data is the last line) gets a broken file and no error.
Version
swamp 20260929.002922.0-sha.55e2ef29, Linux x86_64, local_encryption vault. We saw it first on a sops-age vault (@zocc/sops-age) with a kubeconfig: 3445 of 5707 bytes returned, last line 2261 chars.
Minimal reproduction (throwaway repo)
swamp repo init && swamp vault create local_encryption tv
for n in 1020 1021 1500; do
python3 -c "import sys;sys.stdout.write('a: b\nk: '+'x'*$n)" > c_$n # last line = n+3 chars, no trailing newline
swamp vault put tv t$n --force < c_$n
echo "n=$n file=$(wc -c < c_$n) read=$(swamp vault read-secret tv t$n --yes --quiet | wc -c)"
doneMeasured:
| last line | trailing \n | stored (bytes) | read-secret to a pipe | --json value |
terminal (script -qc) |
|---|---|---|---|---|---|
| 1023 chars | no | 1028 | 1028 OK | - | - |
| 1024 chars | no | 1029 | 5 (first line only) | - | - |
| 1503 chars | no | 1508 | 5 | 1508 OK | 1508 + newline OK |
| 2264 chars | yes | 2307 | 2307 OK | - | - |
| single line, 3000 chars | no | 3000 | 3000 OK | - | - |
The same happens without --quiet, and with output redirected to a file (> out: 5 bytes, empty stderr).
Source
src/presentation/renderers/vault_read_secret.ts:41-46 (same at 55e2ef29 and main bed0772a): a terminal gets writeOutput(value) (console.log), which works. A non-terminal gets Deno.stdout.writeSync(encoder.encode(value)), which loses the line. writeSync returns the number of bytes written and may write only part of the buffer, and the return value is not checked. I did not find why the cut falls exactly at the last line.
Expected
The full value on every output path, or a non-zero exit if the write is short. Suggested: loop until every byte is written (writeAllSync-style).
Workaround
Read with --json and extract .value.
Shipped
Click a lifecycle step above to view its details.
skunk-ape commented 10/5/2026, 2:05:28 PM
Thanks @randybias for reporting this! We shipped: Make the piped and file-redirected output of swamp vault read-secret write the whole secret. The non-terminal path calls Deno.stdout.writeSync once and ignores the returned byte count; Deno's line-buffered stdout writer returns a short count when the trailing partial line is 1024+ bytes, so the last line is dropped with exit 0. Loop until every byte is written, fail loudly on a zero-byte write, add renderer unit tests with a short-writing mock, and prove it end to end with the filed swamp-uat#521 test against the compiled binary.. The fix has been merged and a release is on its way. We appreciate your contribution to swamp.
Sign in to post a ripple.