Skip to content

Handle InvalidOperationException from Console.ReadKey #3744

@jazzdelightsme

Description

@jazzdelightsme

Description of the new feature/enhancement

Under certain (unexpected) circumstances the Console.ReadKey and KeyAvailable APIs can throw an InvalidOperationException. See: dotnet/runtime#88697

(TL;DR: if a second process attached to the console is also waiting for input, and then is terminated, .NET gets back 0 records, and decides to throw.)

Ideally, that bug would be fixed in .NET. However, it is unclear when or if that will happen. I would like to propose that we update PSReadLine's use of these APIs to handle these situations instead of crashing.

For those who know what "razzle" is: the end goal here is to fix ctrl+c in PowerShell razzle.

(For those who don't know: "razzle" is an internal build environment, in which it is not too hard to hit the situation described in dotnet/runtime#88697.)

Proposed technical implementation details

The general idea is simple: wrap in a try/catch, and if it fails, just reissue the call.

One possible wrinkle: those APIs are expected to throw if the "application does not have a console or when console input has been redirected". I would not expect PSReadLine to come into play at all in such a case. Since a user script/module has no opportunity to catch the exception, such an exception should always crash the process. But it could be possible that someone is depending on this behavior (to crash in a console-input-redirected case)... in which case, we could try to detect this (not sure off the top of my head how) or adopt a heuristic, like "if the operation throws 5 times in a row, give up and let the exception fly". Let me know if you think going to such lengths is necessary.

Exhibit A: stack trace when the problem is hit:

An error has occurred that was not properly handled. Additional information is shown below. The PowerShell process will exit.
Unhandled exception. System.InvalidOperationException: Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read.
   at System.ConsolePal.ReadKey(Boolean intercept)
   at Microsoft.PowerShell.PSConsoleReadLine.ReadOneOrMoreKeys()
   at Microsoft.PowerShell.PSConsoleReadLine.ReadKeyThreadProc()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions