Skip to content

Report a missing or blank Command Id or Name in JSON as a JsonException [patch] - #228

Open
matt-edmondson wants to merge 1 commit into
mainfrom
fix/226-command-json-exception
Open

matt-edmondson wants to merge 1 commit into
mainfrom
fix/226-command-json-exception

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #226

What was wrong

Command's [JsonConstructor] was its public constructor. That constructor calls Ensure.NotNull and throws ArgumentException for blank values. So JsonSerializer.Deserialize<Command> threw ArgumentNullException / ArgumentException for {"Name":"Save"}, {"Id":" ","Name":"Save"}, {"Id":"file.save"} and {"Id":"file.save","Name":""}. A host handling bad input with catch (JsonException) would crash on them. Chord, Phrase and Profile already report malformed JSON as a JsonException through JsonArguments.

Change

  • [JsonConstructor] moves off the public constructor to a new private one. The private constructor checks Id and Name with JsonArguments.RequireText, then delegates to the public constructor, so trimming and normalization stay the same.
  • The private constructor takes name before id. That is the only way to make its signature differ from the public one while keeping the property types the serializer binds by. System.Text.Json binds parameters by name, so the order doesn't matter to it. A comment says so.
  • The public constructor still throws ArgumentException, as documented.

Tests

  • New CommandJsonValidationTests:
    • The four inputs from the issue, plus explicit null Id/Name, each expect JsonException.
    • Valid JSON is still trimmed and normalized the way the public constructor does it.
    • The public constructor still throws ArgumentException.
  • With the Command.cs change reverted, all 6 JsonException cases fail. With it, the full suite passes: 389/389 on Linux / .NET 10. Keybinding.sln builds with 0 warnings.

Generated by Claude Code

…on [patch]

Command's [JsonConstructor] was its public constructor, so deserializing
{"Name":"Save"} or {"Id":"  ","Name":"Save"} threw ArgumentNullException or
ArgumentException. Chord, Phrase and Profile report malformed JSON as a
JsonException through JsonArguments; Command now does too, through a private
[JsonConstructor] that checks Id and Name with JsonArguments.RequireText and
then delegates to the public constructor's normalization.

Fixes #226

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW3JF2xHwwm6qrw3Bh7
@sonarqubecloud

sonarqubecloud Bot commented Nov 6, 2026

Copy link
Copy Markdown

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.

Deserializing a Command with a missing or blank Id/Name throws ArgumentException instead of JsonException, unlike Chord, Phrase and Profile

2 participants