{"record":{"id":"79bb18a85dc0a30f","repo":"hashicorp/nomad","slug":"error-changing-owner-group-w","errorCode":null,"errorMessage":"error changing owner/group: %w","messagePattern":"error changing owner/group: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/hostvolumemanager/host_volume_plugin.go","lineNumber":160,"sourceCode":"\tif err != nil {\n\t\tlog.Error(\"error setting directory permission mode\", \"error\", err)\n\t\treturn nil, fmt.Errorf(\"error setting directory permission mode: %w\", err)\n\t}\n\n\tif runtime.GOOS != \"windows\" {\n\t\t// Chown note: A uid or gid of -1 means to not change that value.\n\t\tif err = os.Chown(path, params.Uid, params.Gid); err != nil {\n\t\t\tlog.Error(\"error changing owner/group\", \"error\", err, \"uid\", params.Uid, \"gid\", params.Gid)\n\n\t\t\t// Failing to change ownership is fatal for this plugin. Since we have\n\t\t\t// already created the directory, we should attempt to clean it.\n\t\t\t// Otherwise, the operator must do this manually.\n\t\t\tif err := os.RemoveAll(path); err != nil {\n\t\t\t\tlog.Error(\"failed to remove directory after create failure\",\n\t\t\t\t\t\"error\", err)\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"error changing owner/group: %w\", err)\n\t\t}\n\t}\n\n\tlog.Debug(\"plugin ran successfully\")\n\treturn resp, nil\n}\n\nfunc decodeMkdirParams(in map[string]string) (HostVolumePluginMkdirParams, error) {\n\t// default values if their associated keys are not in the input map\n\tout := HostVolumePluginMkdirParams{\n\t\tMode: 0o700, // \"0700\"\n\t\tUid:  -1,    // this default translates to \"do not set\" in os.Chown\n\t\tGid:  -1,    // ditto\n\t}\n\tvar err error\n\n\tfor param, val := range in {\n\t\tswitch param {","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/hostvolumemanager/host_volume_plugin.go#L142-L178","documentation":"This error wraps a failure of os.Chown during the plugin Create operation on non-Windows platforms, after mkdir and chmod succeeded. Nomad attempts to set the requested uid/gid on the directory; on failure it removes the half-created directory (RemoveAll) and returns this wrapped error. The usual wrapped cause is EPERM: the nomad client process lacks the privileges (root or CAP_CHOWN) to change ownership to the requested uid/gid.","triggerScenarios":"Plugin Create runs on Linux/Unix with nonzero params.Uid or params.Gid while the nomad agent runs as an unprivileged user: os.Chown(path, params.Uid, params.Gid) returns EPERM. Also fires on EINVAL if uid/gid are out of range, or if the path vanished between chmod and chown.","commonSituations":"Operator requests a volume owned by uid 1000/gid 1000 but the nomad client agent runs as the 'nomad' user without root; containers/nomad running without CAP_CHOWN; requesting a uid that only root may set.","solutions":["Run the nomad client as root or grant it CAP_CHOWN (setcap cap_chown+eip on the agent binary / run agent privileged) so chown of arbitrary uids succeeds.","Request uid/gid values the agent user can set — either omit uid/gid (default to agent user) or align them with the agent's own uid/gid.","Set client option to allow unprivileged chown is not possible: alternatively pre-create the directory with correct ownership outside Nomad and create the volume over it.","Check the wrapped error for EPERM vs EINVAL to distinguish privilege vs argument problems."],"exampleFix":"// before: agent runs as 'nomad' user, cannot chown\nUid: 1000, Gid: 1000  // EPERM\n\n// after: run client with capability\n// sudo setcap cap_chown+eip /usr/bin/nomad  (or run agent as root)\n// or omit ownership:\nUid: -1, Gid: -1","handlingStrategy":"try-catch","validationCode":"func canChown(uid, gid int) error {\n    if uid == -1 && gid == -1 {\n        return nil\n    }\n    if os.Geteuid() == 0 {\n        return nil\n    }\n    if uid != -1 && uid != os.Geteuid() {\n        return fmt.Errorf(\"running as uid %d; cannot chown to %d without CAP_CHOWN\", os.Geteuid(), uid)\n    }\n    if gid != -1 && gid != os.Getegid() {\n        return fmt.Errorf(\"running as gid %d; cannot chgrp to %d without CAP_CHOWN\", os.Getegid(), gid)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"var hvErr *hvapi.Error\nif errors.As(err, &hvErr) && strings.Contains(hvErr.Error(), \"error changing owner/group\") {\n    if errors.Is(err, fs.ErrPermission) {\n        // run agent as root / grant CAP_CHOWN, or drop uid/gid from the request\n    }\n}","preventionTips":["Run the nomad client agent as root or with CAP_CHOWN if volumes request specific uid/gid.","Omit uid/gid (use -1) unless ownership changes are genuinely required.","Pre-create directories with correct ownership outside Nomad when the agent is unprivileged.","Validate requested uid/gid against what the agent user may set before submitting the request."],"tags":["filesystem","chown","permissions","host-volumes","linux"],"backgroundTag":"chown-operation-not-permitted","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}