Inquirer.js
Inquirer.js copied to clipboard
If no value is provided list prompt fails with TypeError: Cannot read property 'value' of undefined
The full stack trace is
TypeError: Cannot read property 'value' of undefined
at Prompt.getCurrentValue (/opt/local/lib/node_modules/yo/node_modules/yeoman-environment/node_modules/inquirer/lib/prompts/list.js:123:51)
at tryCatcher (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:63:31)
at InnerObserver.next (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5407:43)
at InnerObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:1762:31)
at InnerObserver.tryCatcher (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:63:31)
at AutoDetachObserverPrototype.next (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5883:51)
at AutoDetachObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:1762:31)
at TakeObserver.next (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5646:17)
at TakeObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:1762:31)
at TakeObserver.tryCatcher (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:63:31)
at AutoDetachObserverPrototype.next (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5883:51)
at AutoDetachObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:1762:31)
at Subject.Rx.Subject.addProperties.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5998:19)
at Subject.tryCatcher (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:63:31)
at AutoDetachObserverPrototype.next (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5883:51)
at AutoDetachObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:1762:31)
at AutoDetachObserver.tryCatcher (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:63:31)
at AutoDetachObserverPrototype.next (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:5883:51)
at AutoDetachObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.js:1762:31)
at Interface.handler (/opt/local/lib/node_modules/yo/node_modules/rx/dist/rx.async.js:482:11)
at emitOne (events.js:77:13)
at Interface.emit (events.js:169:7)
at Interface._onLine (readline.js:211:10)
at Interface._line (readline.js:550:8)
at Interface._ttyWrite (readline.js:827:14)
at ReadStream.onkeypress (readline.js:106:10)
at emitTwo (events.js:92:20)
at ReadStream.emit (events.js:172:7)
at emitKeys (readline.js:1251:14)
at next (native)
at ReadStream.onData (readline.js:919:36)
at emitOne (events.js:77:13)
at ReadStream.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:153:18)
at ReadStream.Readable.push (_stream_readable.js:111:10)
at TTY.onread (net.js:531:20)
The code that causes this is
return that.prompt([{
// Put config prompts here
type : 'list',
name : 'base',
choices : versions,
message : 'Select a version',
default : config.base,
}])
The exception occurs immediately after hitting enter without selecting a value. I attempted to add a validate
function to catch the empty value but the exception occurred before it was called.
what is versions
here? Any chance one of the value in the array is undefined
?
So it turns out that the code I was reviewing set the default
value to the label of the option not the value of the option. So this particular case was simple developer error. Though it does leave open the fact that the developer needs to verify that the default value exists within the choices otherwise you get an exception. That's a different problem from what I described, but I think the hard error is somewhat problematic.
Just found in v3.3.0
readline.js:981
throw err;
^
TypeError: Cannot read property 'value' of undefined
Will see if I can mitigate with a default value per @wwhurley
This is not exactly relevant but perhaps it could be a part of a wider improvement to handle null
and undefined
's for better dev experience, which could be separated out into an individual issue.
I think it's not unreasonable for the Choices
object to handle false
, null
, undefined
within the array, in a reasonable way.
How I'd like to use it (made up):
const choices = [
{ key: 's', name: "Skip", value: 'skip' },
condition ? { key: 'c', name: 'Continue', value: 'continue' } : null, // <- this
{ key: 's', name: "Stop", value: 'stop' }
]
Error call stack (trimmed):
TypeError: Cannot read property 'type' of null
at Choices.choices.choices.map.val (<project>/node_modules/inquirer/lib/objects/choices.js:17:15)
at Array.map (<anonymous>)
at new Choices (<project>/node_modules/inquirer/lib/objects/choices.js:16:28)
...
Currently I push to the choices array, and if I want it to appear in a specific location I'd need to reconstruct the array somehow, meh.
Unless there's a different approach of how to do this within Inquirer.
Thanks 🙂
@dddom you can just do choices.filter(Boolean)
to remove the falsy value from your array.
We recently got a similar error with the Amplify CLI, the root cause is that if you pass in the []
list of choices, then
getCurrentValue() {
return this.opt.choices.getChoice(this.selected).value;
}
fails as getChoice
returned undefined hence no items in the line so no selection, I think that something like this would fix it:
getCurrentValue() {
const selection = this.opt.choices.getChoice(this.selected);
return selection ?? selection.value;
}
On the other hand since inquirer is based on RXJS in the caller code it ends up as an UnhandledPromiesRejectionWarning
, which is not the nicest thing and the stacktrace for the error has nothing to do with the actual call chain because of the nature of how EventEmitter
fired events work:
(node:96356) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'value' of undefined
at ListPrompt.getCurrentValue (/Users/attila/workspaces/amplify-cli/node_modules/inquirer/lib/prompts/list.js:148:53)
at MapSubscriber._next (/Users/attila/workspaces/amplify-cli/node_modules/rxjs/internal/operators/map.js:49:35)
at MapSubscriber.Subscriber.next (/Users/attila/workspaces/amplify-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
at TakeSubscriber._next (/Users/attila/workspaces/amplify-cli/node_modules/rxjs/internal/operators/take.js:54:30)
at TakeSubscriber.Subscriber.next (/Users/attila/workspaces/amplify-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
at Interface.handler (/Users/attila/workspaces/amplify-cli/node_modules/rxjs/internal/observable/fromEvent.js:22:28)
at Interface.emit (events.js:327:22)
at Interface.EventEmitter.emit (domain.js:486:12)
at Interface._onLine (readline.js:337:10)
at Interface._line (readline.js:666:8)
at Interface._ttyWrite (readline.js:1010:14)
at ReadStream.onkeypress (readline.js:213:10)
at ReadStream.emit (events.js:327:22)
at ReadStream.EventEmitter.emit (domain.js:486:12)
at emitKeys (internal/readline/utils.js:345:14)
at emitKeys.next (<anonymous>)
at ReadStream.onData (readline.js:1144:36)
at ReadStream.emit (events.js:315:20)
at ReadStream.EventEmitter.emit (domain.js:486:12)
at addChunk (_stream_readable.js:309:12)
at readableAddChunk (_stream_readable.js:284:9)
at ReadStream.Readable.push (_stream_readable.js:223:10)
at TTY.onStreamRead (internal/stream_base_commons.js:188:23)
at TTY.callbackTrampoline (internal/async_hooks.js:129:14)