{"id":"57dfe3c122b1bdac","repo":"docker/cli","slug":"the-password-stdin-option-requires-username-to","errorCode":null,"errorMessage":"the --password-stdin option requires --username to be set","messagePattern":"the --password-stdin option requires --username to be set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/registry/login.go","lineNumber":80,"sourceCode":"\tflags := cmd.Flags()\n\n\tflags.StringVarP(&opts.user, \"username\", \"u\", \"\", \"Username\")\n\tflags.StringVarP(&opts.password, \"password\", \"p\", \"\", `Password or Personal Access Token (PAT), or \"-\" to read from stdin`)\n\tflags.BoolVar(&opts.passwordStdin, \"password-stdin\", false, \"Take the Password or Personal Access Token (PAT) from stdin\")\n\n\treturn cmd\n}\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","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/docker/cli/blob/e9452d6e785f6e365712b9d71bd7517591773c86/cli/command/registry/login.go#L62-L98","documentation":"Raised by verifyLoginFlags (cli/command/registry/login.go:80). When the password comes from stdin, the CLI cannot also prompt interactively for a username, because stdin is already consumed by the secret — so --username must be provided as a flag up front.","triggerScenarios":"docker login --password-stdin registry.example.com < token.txt without -u/--username; equivalently docker login -p - < token.txt with no username flag. Triggered purely at flag-parse time, before stdin is read.","commonSituations":"CI jobs that store only a token secret and forget the username variable; copy-pasted login snippets missing the -u flag; assuming the username will be taken from a previous login's config.json (it is not for --password-stdin).","solutions":["Add the username flag: echo \"$TOKEN\" | docker login -u \"$USERNAME\" --password-stdin","For registries with token-only auth schemes (e.g. AWS ECR uses AWS as the username, GHCR accepts your GitHub username), pass the scheme's expected username explicitly"],"exampleFix":"# before\necho \"$TOKEN\" | docker login --password-stdin ghcr.io\n\n# after\necho \"$TOKEN\" | docker login -u my-github-user --password-stdin ghcr.io","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["docker-cli","registry","authentication","flag-validation","stdin"],"analyzedSha":"e9452d6e785f6e365712b9d71bd7517591773c86","analyzedAt":"2026-08-01T07:09:22.474Z","schemaVersion":2}