Skip to content

Improve error messages for invalid binary strings#16688

Merged
sholderbach merged 5 commits intonushell:mainfrom
Sheape:improve-error-msg-binary-str
Sep 17, 2025
Merged

Improve error messages for invalid binary strings#16688
sholderbach merged 5 commits intonushell:mainfrom
Sheape:improve-error-msg-binary-str

Conversation

@Sheape
Copy link
Copy Markdown
Contributor

@Sheape Sheape commented Sep 15, 2025

Fixes #9566. Based on the decision from this PR #16678, instead of dealing with out-of-range octal strings, throwing a specific error is better.

Let me know if these error messages are too detailed and prefer just having a single "out-of-range error".

Release notes summary - What our users need to know

Improved error messages for binary literals

Previously, a generic shell error is thrown for invalid binary strings. Now, an improve error message is thrown for invalid binary, hexadecimal, and octal strings.

> 0b[121]
# => Error: nu::parser::invalid_binary_string
# => 
# => × Invalid binary string.
# =>   ╭─[entry #1:1:1]
# => 1 │ 0b[121]
# =>   · ───┬───
# =>   ·    ╰── invalid binary string
# =>   ╰────
# =>  help: binary strings may contain only 0 or 1.

Tasks after submitting

  • N/A

@github-actions github-actions bot added the A:parser Issues related to parsing label Sep 15, 2025
@Sheape Sheape force-pushed the improve-error-msg-binary-str branch from 63f6b30 to a06b11e Compare September 15, 2025 09:39
@Sheape
Copy link
Copy Markdown
Contributor Author

Sheape commented Sep 15, 2025

Sorry if I had to forced-push 😓. I had to resolve merge conflicts from Rust 1.88.0 PR.

Copy link
Copy Markdown
Member

@sholderbach sholderbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this, looks good to me for the most part.

Welcome a second set of eyes regarding the integration into the chain of which erorrs are raised or fall back into a different parse.

Comment on lines +111 to +114
} else if !matches!(
working_set.parse_errors.last(),
Some(ParseError::Expected(_, _))
) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By looking at just the diff I can't immediately tell why this (negative) match is OK to pass with error suppresion.

Can you explain that briefly? Maybe it is worth adding a comment or a different match here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to how parse_number matches (except without error supression). Before this change, the parser actually does not stop parsing and treats invalid binary strings as GlobPattern which is why I have to catch if the error is unexpected if that makes sense.

pub fn parse_number(working_set: &mut StateWorkingSet, span: Span) -> Expression {
let starting_error_count = working_set.parse_errors.len();
let result = parse_int(working_set, span);
if starting_error_count == working_set.parse_errors.len() {
return result;
} else if !matches!(
working_set.parse_errors.last(),
Some(ParseError::Expected(_, _))
) {
} else {
working_set.parse_errors.truncate(starting_error_count);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The section you quoted is a horrible double negation with that empty else if ! branch.

I was confused for a second why the truncation in your code was fine but it makes sense in the is_math_expression_like hack where we don't want to leave errors.

If I understand the codepaths correctly the !matches on Expected filters down to just your newly created variant for InvalidBinaryString? Then I think it would make sense to use that and maybe add a comment why we choose to deviate here from the rest of the is_math_expression_like chain.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops my bad, I genuinely thought that empty else if ! branch had a purpose (which was to not clear unexpected parsing integer error and fall through float parsing).

Yeah only that InvalidBinaryString variant should hit that codepath, or alternatively I can modify it to just strictly check if it matches InvalidBinaryString.

I'll add comments for this so people wouldn't get confused.

Comment on lines +1723 to +1726
2 => "binary strings may contain only 0 or 1.",
8 => "octal strings must have a length that is a multiple of three and contain values between 0o000 and 0o377.",
16 => "hexadecimal strings may contain only the characters 0–9 and A–F.",
_ => "", // radix other than 2, 8, or 16 is an invalid radix
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for elaborating in the messages.

Defensively you can throw the text of the comment with something like INTERNAL ERROR: into the fall through arm. If there is ever something going wrong being loud about it can be helpful even if it is vanishingly likely to break.

Comment on lines +216 to +218
#[error("Invalid binary string.")]
#[diagnostic(code(nu::parser::invalid_binary_string), help("{1}"))]
InvalidBinaryString(#[label("invalid binary string")] Span, String),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit of a stylistic question if we need a completely separate variant for that or if we can cover it with our existing variants and some additional text (cc @cptpiepmatz )

sholderbach added a commit to sholderbach/nushell that referenced this pull request Sep 17, 2025
This `else if` branch being empty makes no sense if there is no comment.
Can be collapsed by removing the negation on the `matches!`

Stumbled over this while reading nushell#16688 (comment)
Copy link
Copy Markdown
Member

@sholderbach sholderbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After you can take a stab at the comment, clear to land from my side

@sholderbach sholderbach merged commit 4062cbd into nushell:main Sep 17, 2025
16 checks passed
@github-actions github-actions bot added this to the v0.108.0 milestone Sep 17, 2025
@sholderbach sholderbach added notes:ready The "Release notes summary" section of this PR is ready to be included in our release notes. notes:other Include the release notes summary in the "Other changes" section labels Sep 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A:parser Issues related to parsing notes:other Include the release notes summary in the "Other changes" section notes:ready The "Release notes summary" section of this PR is ready to be included in our release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0o[777] is not working

2 participants