valuesource: the env provider does not trim, so a trailing newline reaches the auth header and Go refuses the request #304
Labels
No labels
burndown-2026-06
sunday-sprint
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/umbra#304
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while debugging a live Discord MCP wrap that had stopped making outbound calls. The failure is silent in an unhelpful way, and the fix is one call.
The asymmetry
pkg/valuesource/valuesource.go,Builtins():filetrims because files carry trailing newlines.envdoes not, even though an env var is very often a file's contents one hop removed.Why one hop removed is the common case
The path that produced this:
aws ssm put-parameter --value file://..., which is the recommended form precisely because it keeps the value out of argv. The file has a trailing newline, because editors add one.secretKeyRef, unchanged.value env "TOKEN"in a guardfile resolves it, unchanged.Every layer is faithful, which is correct behavior for all of them, and the newline arrives intact.
What it does downstream
http/opcore/runtime.go:149:Go's transport validates header values on write, so the request never leaves the process:
This is the part that makes it expensive to diagnose. There is no 401 and no upstream log line, because the upstream is never contacted. From the operator's side a tool simply fails, and the natural first guess is a bad credential or a permissions problem rather than a whitespace problem. The credential is correct. It is also unprintable, so the usual instinct of echoing it to compare is both unsafe and unavailable.
Suggested fix
return strings.TrimSpace(v), nilin theenvprovider, matchingfile.Worth considering for
literaltoo, though the argument is weaker: a literal is author-supplied in the guardfile, so trailing whitespace there is more plausibly deliberate and more visible in review.A credential with meaningful leading or trailing whitespace is not a real case for any of the three, and every consumer that has thought about it has landed on trimming independently.
sirens-echodoesstrings.TrimSpace(os.Getenv("DISCORD_TOKEN"))atinternal/community/config.go:903, which is exactly why the same malformed value worked fine through its gateway connection while failing through the guardfile.Alternative worth weighing
Reject rather than trim: fail closed at resolve time with an error naming the variable and the offending character class, never the value. That surfaces the operator's mistake instead of silently correcting it, and a credential is the wrong place to be quietly lenient.
Trimming matches
file's existing behavior and fixes every deployment already carrying the newline without an operator round trip. Rejecting is more honest but strands anyone whose stored value has one. Either beats the current state, where the value is neither trimmed nor refused. Filing with a recommendation of trim, for consistency withfile, but the call is not mine.Repro
Observed against umbra
v0.154.0, the versionmcp-beaverpins.