{"id":"445447c4a09d1464","repo":"docker/cli","slug":"password-is-empty","errorCode":null,"errorMessage":"password is empty","messagePattern":"password is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/registry/login.go","lineNumber":87,"sourceCode":"}\n\n// verifyLoginFlags validates flags set on the command.\n//\n// TODO(thaJeztah); combine with verifyLoginOptions, but this requires rewrites of many tests.\nfunc verifyLoginFlags(flags *pflag.FlagSet, opts loginOptions) error {\n\tif flags.Changed(\"password-stdin\") || opts.password == \"-\" {\n\t\tif flags.Changed(\"password\") && opts.password != \"-\" {\n\t\t\treturn errors.New(\"conflicting options: cannot specify both --password and --password-stdin\")\n\t\t}\n\t\tif !flags.Changed(\"username\") {\n\t\t\treturn errors.New(\"the --password-stdin option requires --username to be set\")\n\t\t}\n\t}\n\tif flags.Changed(\"username\") && opts.user == \"\" {\n\t\treturn errors.New(\"username is empty\")\n\t}\n\tif flags.Changed(\"password\") && opts.password == \"\" {\n\t\treturn errors.New(\"password is empty\")\n\t}\n\treturn nil\n}\n\n// readSecretFromStdin reads the secret from r and returns it as a string.\n// It trims terminal line-endings (LF, CRLF, or CR), which may be added when\n// inputting interactively or piping input. The value is otherwise treated as\n// opaque, preserving any other whitespace, including newlines, per [NIST SP 800-63B §5.1.1.2].\n// Note that trimming whitespace may still happen elsewhere (see [NIST SP 800-63B (revision 4) §3.1.1.2]);\n//\n// > Verifiers **MAY** make limited allowances for mistyping (e.g., removing\n// > leading and trailing whitespace characters before verification, allowing\n// > the verification of passwords with differing cases for the leading character)\n//\n// [NIST SP 800-63B §5.1.1.2]: https://pages.nist.gov/800-63-3/sp800-63b.html#memsecretver\n// [NIST SP 800-63B (revision 4) §3.1.1.2]: https://pages.nist.gov/800-63-4/sp800-63b.html#passwordver\nfunc readSecretFromStdin(r io.Reader) (string, error) {\n\tb, err := io.ReadAll(r)","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/docker/cli/blob/e9452d6e785f6e365712b9d71bd7517591773c86/cli/command/registry/login.go#L69-L105","documentation":"Raised by verifyLoginFlags (cli/command/registry/login.go:87) when the --password/-p flag was explicitly set but its value is an empty string. An explicitly empty password is rejected at parse time instead of being sent to the registry or triggering a prompt.","triggerScenarios":"docker login -u user -p '' registry.example.com; docker login --password=\"\" — pflag reports the flag as Changed while opts.password is \"\". Most often docker login -p \"$PASS_VAR\" with PASS_VAR empty or unset.","commonSituations":"Empty CI secrets (secret not available to the branch/fork running the job); credential-fetch commands substituted inline that failed silently, e.g. -p \"$(vault read ... )\" returning nothing; .env files not loaded before the login step.","solutions":["Confirm the password variable is non-empty before use: docker login -u user -p \"${PASS:?PASS is empty}\" (or better, switch to --password-stdin)","Prefer --password-stdin, which both avoids the process-list exposure warning and gives a clearer failure mode: printf '%s' \"$PASS\" | docker login -u user --password-stdin","If the value comes from a command substitution, run that command separately first and check its exit code and output"],"exampleFix":"# before (PASS unset → empty flag value)\ndocker login -u user -p \"$PASS\" registry.example.com\n\n# after\nprintf '%s' \"${PASS:?PASS is empty}\" | docker login -u user --password-stdin registry.example.com","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["docker-cli","registry","authentication","flag-validation","environment-variables"],"analyzedSha":"e9452d6e785f6e365712b9d71bd7517591773c86","analyzedAt":"2026-08-01T07:09:22.474Z","schemaVersion":2}