Skip to content

[Bug] password prompt resolves undefined on empty submit #560

Description

@jgoux

Environment

  • OS: macOS / Darwin arm64
  • Node Version: v24.16.0
  • Package: @clack/prompts, @clack/core
  • Package Version: @clack/prompts@1.5.1, @clack/core@1.4.1

Describe the bug

Submitting an empty password() prompt can resolve undefined, even though the public type signature is Promise<string | symbol>.

This is surprising because the prompt result is typed as a string after isCancel(result) is checked, so code like this type-checks but can throw at runtime when the user presses Enter without typing a password:

const value = await password({ message: "Password" });
if (!isCancel(value)) {
  value.trim(); // Type-checks, but can throw if value is undefined.
}

This also differs from text(), which resolves "" for an empty submit.

Looking at the current source, TextPrompt has a finalize handler that normalizes a missing value to "", while PasswordPrompt only updates its value from userInput and does not appear to perform the same empty-submit normalization.

To Reproduce

Minimal manual reproduction:

import { password, text } from "@clack/prompts";

const passwordValue = await password({ message: "Password" });
console.log("password", { type: typeof passwordValue, value: passwordValue });

const textValue = await text({ message: "Text" });
console.log("text", { type: typeof textValue, value: textValue });

Steps to reproduce the behavior:

  • Run the script in a TTY.
  • Press Enter at the password prompt without typing anything.
  • Press Enter at the text prompt without typing anything.

Observed result:

password { type: "undefined", value: undefined }
text { type: "string", value: "" }

I also reproduced this with a fake TTY by emitting a Return keypress against the prompt input stream; the password() result was undefined while text() returned "".

Expected behavior

password() should either:

  • resolve "" on empty submit, matching text() and the current Promise<string | symbol> type, or
  • include undefined in its public return type if undefined is intentional behavior.

The first option seems more consistent with the documented behavior that the password prompt behaves like the text prompt, but masked.

Additional Information

This surfaced downstream because strict TypeScript did not warn about .trim() after isCancel() handling. The dependency type says password() returns only string | symbol, but runtime can produce undefined for empty password input.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    Status
    Needs triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions