Skip to content

Handle empty-string and null-value results returned from custom argument completer more properly#27398

Merged
daxian-dbw merged 7 commits into
PowerShell:masterfrom
daxian-dbw:completion-fix
May 11, 2026
Merged

Handle empty-string and null-value results returned from custom argument completer more properly#27398
daxian-dbw merged 7 commits into
PowerShell:masterfrom
daxian-dbw:completion-fix

Conversation

@daxian-dbw
Copy link
Copy Markdown
Member

@daxian-dbw daxian-dbw commented May 5, 2026

PR Summary

The constructor of CompletionResult doesn't allow an empty string argument. Exception will be thrown if an empty string is passed in.

For example, with an argument completer defined like this (or, use return $null):

register-ArgumentCompleter -Native -CommandName ping -ScriptBlock {
    param($WordToComplete, $CommandAst, $CursorPosition)
    return ''
}

You will get an exception when calling TabExpansion2 for ping:

PS:49> $result = TabExpansion2 -inputScript 'ping ' -cursorColumn 5
MethodInvocationException:
Line |
  40 |  …      return [System.Management.Automation.CommandCompletion]::Complet …
     |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Exception calling "CompleteInput" with "3" argument(s): "Cannot process argument because the value of argument "completionText" is null. Change the value of argument "completionText" to a non-null value."

This PR improves how InvokeScriptArgumentCompleter handles the return values from a custom argument completer script block:

  1. Avoid ArgumentException or NullReferenceException when the return values include null or empty string.
  2. Today, when a custom completer returns $null or an empty string, due to the exception (which gets swallowed by PSReadLine), the user-perceived behavior is -- no result, and default completion (e.g. file names) is suppressed. So, it's not uncommon for developers to intentionally depend on this behavior suppress file name completion.
    • This behavior is explicitly preserved -- when a custom completer script block returns $null or empty string, the completion is considered successfully, and we will not fall back to default completions.

PR Checklist

Copilot AI review requested due to automatic review settings May 5, 2026 17:26
@daxian-dbw daxian-dbw requested a review from a team as a code owner May 5, 2026 17:26
@daxian-dbw daxian-dbw added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label May 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the tab-completion pipeline against invalid output from script-based argument completers by filtering out results that would otherwise cause CompletionResult construction to throw, improving completion robustness for custom/native registered completers.

Changes:

  • Skip null items returned from ScriptBlock.Invoke() results when processing custom completer output.
  • Ignore empty-string ("") string results from custom completers to avoid CompletionResult(string) throwing.
  • Change the internal “handled” return value to reflect whether any valid completion items were actually added.

Comment thread src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs Outdated
@SeeminglyScience
Copy link
Copy Markdown
Contributor

So somewhat complicating the matter, I've seen some folks think that returning an empty string (or null) is what allows them to "disable" the fallback file path completion. They are likely not aware that it is due to an exception being thrown.

I don't know if that's a good enough reason not to fix the clearly broken code here but it is worth mentioning we'd likely get quite a few confused issues if the behavior changes.

@daxian-dbw
Copy link
Copy Markdown
Member Author

That's a good point. I think we should keep that behavior, but in a more explicit way instead of depending on the exception :)
I will update the changes.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

@daxian-dbw daxian-dbw changed the title Ignore empty string result returned from custom argument completer Handle empty-string and null-value results returned from custom argument completer more properly May 6, 2026
Copy link
Copy Markdown
Contributor

@SeeminglyScience SeeminglyScience left a comment

Choose a reason for hiding this comment

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

LGTM!

@daxian-dbw daxian-dbw merged commit c9ac205 into PowerShell:master May 11, 2026
42 checks passed
@daxian-dbw daxian-dbw deleted the completion-fix branch May 11, 2026 18:59
JustinGrote pushed a commit to JustinGrote/PowerShell that referenced this pull request Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants