docker/cli · error
invalid mode specified
Error message
invalid mode specified: %v
What it means
Thrown by swarmopts.SecretOpt.Set when the 'mode=<value>' field of a --secret / --secret-add secret reference cannot be parsed as a 32-bit unsigned integer. The value is parsed with strconv.ParseUint(val, 0, 32): base 0 means an unprefixed number is treated as DECIMAL, while '0o444' (octal), '0x..' (hex), or a legacy leading-zero '0444' are honored. Anything non-numeric, negative, or exceeding 2^32-1 fails here.
Solutions
- Prefix octal modes with 0o (Go base-0 octal): use 'mode=0o444' instead of 'mode=444'.
- If you really mean decimal, keep the integer in range 0..4294967295 (e.g. 'mode=292' for 0o444).
- Do not use symbolic chmod notation (rwx, u=rw); convert it to a numeric mode first with a umask/chmod tool.
Example fix
# before docker service create --secret source=db,mode=444 # after # 0o prefix => base-0 parses octal => 0o444 == r--r--r-- docker service create --secret source=db,mode=0o444
Defensive patterns
Strategy: validation
Validate before calling
// Validate the mode= field of a --secret value (Go base-0 semantics) BEFORE calling SecretOpt.Set.
import ("strconv"; "strings")
func validSecretMode(opt string) bool {
for _, f := range strings.Split(opt, ",") {
k, v, ok := strings.Cut(f, "=")
if !ok || !strings.EqualFold(strings.TrimSpace(k), "mode") {
continue
}
_, err := strconv.ParseUint(strings.TrimSpace(v), 0, 32) // base 0, 32-bit, like opts
return err == nil
}
return true // no mode field -> default 0o444
}
// usage:
// if !validSecretMode(input) { return fmt.Errorf("bad secret mode: %s", input) } Try / catch
// secretOpt is a pflag.Value; Set returns the error directly.
if err := secretOpt.Set(input); err != nil {
// err already contains: invalid mode specified: <strconv error>
return fmt.Errorf("invalid --secret value %q: %w", input, err)
} Prevention
- Always write secret modes with the 0o octal prefix (mode=0o444) to avoid the base-0 decimal trap.
- Never pass symbolic chmod notation (u=rw, rwx).
- Keep modes within uint32 (0..4294967295).
When it happens
Trigger: Running 'docker service create --secret source=db,mode=444' and expecting octal r--r--r-- (base 0 reads unprefixed '444' as decimal 444 = 0o674, which technically succeeds but is not what was meant). It HARD-fails on 'mode=r--r--r--', 'mode=444x', 'mode=-1', or 'mode=5000000000' (uint32 overflow).
Common situations: Users assume shell chmod-style octal/symbolic notation (e.g. 'mode=444' or 'mode=u=rw') like 'chmod'; copying a mode from a Dockerfile that used JSON '0444'; or passing a file mode larger than uint32. The base-0 quirk silently surprises anyone who expects unprefixed digits to be octal.
Related errors
- node ID not found in /info
- when using secret driver secret data must be empty
- error reading from STDIN: data is empty
- secret file is required
- placement preference must be of the format
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/61d13e6691723d06.
Report an issue: GitHub.
Appendix: source
Thrown at opts/swarmopts/secret.go:61
for _, field := range fields {
key, val, ok := strings.Cut(field, "=")
if !ok || key == "" {
return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
}
// TODO(thaJeztah): these options should not be case-insensitive.
switch strings.ToLower(key) {
case "source", "src":
options.SecretName = val
case "target":
options.File.Name = val
case "uid":
options.File.UID = val
case "gid":
options.File.GID = val
case "mode":
m, err := strconv.ParseUint(val, 0, 32)
if err != nil {
return fmt.Errorf("invalid mode specified: %v", err)
}
options.File.Mode = os.FileMode(m)
default:
return errors.New("invalid field in secret request: " + key)
}
}
if options.SecretName == "" {
return errors.New("source is required")
}
if options.File.Name == "" {
options.File.Name = options.SecretName
}
o.values = append(o.values, options)
return nil
}View on GitHub (pinned to 4f84911bfe)