Skip to content

fix(output): stop HTML-escaping JSON output - #100

Closed
Priyanshu (priyanshu-plivo) wants to merge 3 commits into
mainfrom
fix/json-no-html-escape
Closed

Priyanshu (priyanshu-plivo) wants to merge 3 commits into
mainfrom
fix/json-no-html-escape

Conversation

@priyanshu-plivo

Copy link
Copy Markdown
Contributor

What

Go's JSON encoding HTML-escapes <, > and & into unicode escape sequences. The CLI's JSON output, error envelopes and dry-run prints all showed those escapes:

  • A hint like participant add <name> printed with escaped brackets.
  • URLs with & weren't byte-for-byte what the API returned.
  • A --text 'Tom & Jerry <3' dry-run showed escaped characters.

It's valid JSON, but noisy for people and agents reading the raw output.

Change

  • internal/output:
    • JSONSuccess and JSONError use one encoder with HTML escaping off (SetEscapeHTML(false)). JSONRaw goes through JSONSuccess, so raw API responses are fixed too.
    • New helpers output.Marshal and output.MarshalIndent behave like the encoding/json equivalents with escaping off.
  • Commands that encode JSON themselves now use those helpers: the agents multi-page merge, sip write output (mustJSON), ask -o json, and the ask and auth token dry-run prints.
  • Display-only paths:
    • The request printer used for --dry-run and --log-level debug.
    • Error messages built from unrecognised error bodies.
    • What is sent to the API is unchanged.
  • Formatting is otherwise byte-identical. A differential check of the helpers against encoding/json found no differences apart from the three characters.

Tests

  • Exact-bytes tests for the output writers (error hint, data value, raw response).
  • mustJSON, the multi-page merge (a page-2 name and page 1's next URL with &), the ask -o json renderer, an offline ask --dry-run, the redactor, and the error fallback all failed on the old code with escaped output and pass now.
  • Run locally, all passing: go test -race ./..., golangci-lint run, builds for windows and -tags internal, make docs drift, and scripts/smoke.sh.

encoding/json escapes <, > and & as unicode sequences by default. In
-o json and piped output that garbled hints such as `participant add
<name>` and every & in an API URL, so the bytes no longer matched what
the API returned.

JSONRaw had the same problem: the encoder re-compacts the raw upstream
body and escapes it on the way through. JSONSuccess, JSONRaw and
JSONError now share one encoder with HTML escaping off; indentation and
the trailing newline are unchanged.
The shared writers no longer escape <, > and &, but several commands
still build JSON with encoding/json before it reaches the user:

- agents list --all merges pages by re-encoding them, so names and
  pagination URLs came out escaped
- the -o json result of the SIP write commands
- ask -o json, which streams each server event as a JSON line
- the ask and auth token mint --dry-run request previews
- the JSON pass-through of auth token list (internal build)

output.Marshal and output.MarshalIndent are json.Marshal and
json.MarshalIndent with HTML escaping off, and these sites now use them.
Formatting is otherwise byte-identical.
--dry-run and --log-level debug print request bodies through the
redactor, which re-encodes them, so every API command showed a text
like "Tom & Jerry <3" escaped. An error message built from an
unrecognized error body had the same problem. Both now use
output.Marshal. Only what is displayed changes: request bodies sent to
the API are encoded as before.
@priyanshu-plivo

Copy link
Copy Markdown
Contributor Author

Superseded by #101, which combines this change with the login paste fallback.

@priyanshu-plivo
Priyanshu (priyanshu-plivo) deleted the fix/json-no-html-escape branch September 29, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant