{"record":{"id":"d91dce138c5e64bf","repo":"caddyserver/caddy","slug":"owner-of-the-socket-requires-w-write-octal","errorCode":null,"errorMessage":"owner of the socket requires '-w-' (write, octal: '2') permissions at least; got '%s' in %s","messagePattern":"owner of the socket requires '-w-' \\(write, octal: '2'\\) permissions at least; got '(.+?)' in (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sockets.go","lineNumber":47,"sourceCode":"// Permission bits will default to 0200 if none are specified.\n// Throws an error, if the first carrying bit does not\n// include write perms (e.g. `0422` or `022`).\n// Symbolic permission representation (e.g. `u=w,g=w,o=w`)\n// is not supported and will throw an error for now!\nfunc SplitUnixSocketPermissionsBits(addr string) (path string, fileMode fs.FileMode, err error) {\n\taddrSplit := strings.SplitN(addr, \"|\", 2)\n\n\tif len(addrSplit) == 2 {\n\t\t// parse octal permission bit string as uint32\n\t\tfileModeUInt64, err := strconv.ParseUint(addrSplit[1], 8, 32)\n\t\tif err != nil {\n\t\t\treturn \"\", 0, fmt.Errorf(\"could not parse octal permission bits in %s: %v\", addr, err)\n\t\t}\n\t\tfileMode = fs.FileMode(fileModeUInt64)\n\n\t\t// FileMode.String() returns a string like `-rwxr-xr--` for `u=rwx,g=rx,o=r` (`0754`)\n\t\tif string(fileMode.String()[2]) != \"w\" {\n\t\t\treturn \"\", 0, fmt.Errorf(\"owner of the socket requires '-w-' (write, octal: '2') permissions at least; got '%s' in %s\", fileMode.String()[1:4], addr)\n\t\t}\n\n\t\treturn addrSplit[0], fileMode, nil\n\t}\n\n\t// default to 0200 (symbolic: `u=w,g=,o=`)\n\t// if no permission bits are specified\n\treturn addr, 0o200, nil\n}\n","sourceCodeStart":29,"sourceCodeEnd":57,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/internal/sockets.go#L29-L57","documentation":"After parsing octal permission bits for a unix socket, Caddy requires the owner (first digit triad) to include the write bit. FileMode.String() is inspected and the owner triad must contain 'w'. Modes like 0422 or 002 (read/execute only for the owner) are rejected because the socket owner must be able to write.","triggerScenarios":"Listening on 'unix/path/to/socket|0422' or 'unix/path|0400' — any mode whose owner octal digit lacks the 2 bit (0, 1, 4, 5). Even group/other write bits (e.g. 0042) do not satisfy the requirement; the check is strictly on the owner triad at String()[2].","commonSituations":"Users copy a full chmod-style mode such as 0422 (intended for files where group/other write matters) into the socket address. Or they compute a mode where the owner only gets read (0400) thinking the server only reads the socket.","solutions":["Ensure the owner digit includes write: use 0620, 0600, 0660, 0666, or at minimum 0200.","Drop the permission suffix to get the safe default of 0200 (owner write only).","If sharing the socket with a client process, add group bits rather than removing owner write: 'path|0620'."],"exampleFix":"// before\nunix/run/caddy.sock|0422\n// after: owner write bit set, group read\nunix/run/caddy.sock|0620","handlingStrategy":"validation","validationCode":"func ownerCanWrite(mode uint32) bool {\n    return mode&0o200 != 0\n}\n\n// use before building the address:\n// if !ownerCanWrite(mode) { /* fix mode */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize on modes like 0600, 0620, 0660 for sockets in your tooling.","Treat the owner digit as must-contain-2 in config linters."],"tags":["unix-socket","permissions","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}