openmediavault/openmediavault · error · OMV\Exception

Unauthorized attempt to modify the system group account

Error message

Unauthorized attempt to modify the system group account '%s'

What it means

The rpc.usermgmt.setgroup RPC checks whether the target group exists on the system and is a system group (GID below the system threshold). System groups must not be altered through OMV, so the engine throws this exception before any change is applied.

Solutions

  1. Only target OMV-managed (non-system) groups in setgroup calls.
  2. To manage membership of system groups, use the appropriate user membership RPC or OS tooling (usermod -aG).
  3. Verify the group's GID with getent group and ensure it is above the system range before calling.
  4. Create a new OMV-managed group and use it instead of modifying a system group.

Example fix

// before
$omv->rpc('usermgmt.setGroup', ['name' => 'sudo', 'comment' => 'admins']);
// after
$grp = posix_getgrnam($name);
if ($grp && $grp['gid'] < 1000) { throw new DomainException("system group"); }
$omv->rpc('usermgmt.setGroup', ['name' => $name, 'comment' => 'admins']);
Defensive patterns

Strategy: validation

Validate before calling

$gr = posix_getgrnam($name);
if ($gr !== false && $gr['gid'] < 1000) {
    throw new DomainException("$name is a system group");
}

Type guard

function isSystemGroup(string $name): bool {
    $gr = @posix_getgrnam($name);
    return $gr !== false && $gr['gid'] < 1000;
}

Try / catch

try {
    $omv->rpc('usermgmt.setGroup', $params);
} catch (\OMV\Exception $e) {
    if (str_contains($e->getMessage(), 'system group account')) {
        throw new DomainException("Refusing to modify system group", 0, $e);
    } throw $e;
}

Prevention

When it happens

Trigger: Calling rpc.usermgmt.setgroup with params['name'] set to a system group such as root, sudo, www-data, or a package-created group that exists in /etc/group.

Common situations: Automation trying to add users to 'sudo' or 'www-data' via setgroup instead of user membership RPCs; scripts iterating all groups without filtering system GIDs; name collisions after package installation.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of openmediavault/openmediavault@dce610eb66 (2026-09-15). Data as JSON: /api/errors/7006f38a73d7a926. Report an issue: GitHub.

Appendix: source

Thrown at deb/openmediavault/usr/share/openmediavault/engined/rpc/usermgmt.inc:911

     *   \em name The name of the group.
     *   \em gid The group ID. This field is optional.
     *   \em comment Any text string.
     *   \em members The group members as an array of user names.
     * @param context The context of the caller.
     * @return The stored configuration object.
     */
    public function setGroup($params, $context)
    {
        // Validate the RPC caller context.
        $this->validateMethodContext($context, [
            "role" => OMV_ROLE_ADMINISTRATOR
        ]);
        // Validate the parameters of the RPC service method.
        $this->validateMethodParams($params, "rpc.usermgmt.setgroup");
        // Check if the given group is a system account. Abort this attempt.
        $group = new \OMV\System\Group($params['name']);
        if ($group->exists() && $group->isSystemAccount()) {
            throw new \OMV\Exception(
                "Unauthorized attempt to modify the system group account '%s'",
                $params['name']
            );
        }
        // Try to get existing configuration object.
        $filter = [
            "operator" => "stringEquals",
            "arg0" => "name",
            "arg1" => $params['name']
        ];
        $db = \OMV\Config\Database::getInstance();
        // Does the group already exist in the database?
        $oldObject = null;
        if ($db->exists("conf.system.usermngmnt.group", $filter)) {
            $notifyType = OMV_NOTIFY_MODIFY;
            // Get the group configuration object. Since the name of a group
            // is unique, we can simply use the first object found.
            $object = $oldObject = $db->getByFilter(

View on GitHub (pinned to dce610eb66)