gethomepage/homepage · error · Error

Group '${groupName}' must contain an array

Error message

Group '${groupName}' must contain an array

What it means

Thrown by addService when an existing group is found but the value attached to that group key is not an array. Homepage expects each group to map to a list of service entries; a group mapping to a scalar/object blocks insertion.

Source

Thrown at src/utils/mcp/homepage-mcp.js:211

  const services = parseYamlConfig("services.yaml");
  if (!Array.isArray(services)) {
    throw new Error("services.yaml must contain a top-level array");
  }

  const groupName = args.group.trim();
  const serviceName = args.name.trim();
  const serviceConfig = args.service ?? {};
  assertPlainObject(serviceConfig, "service");

  let group = services.find((entry) => isPlainObject(entry) && Object.keys(entry)[0] === groupName);
  if (!group) {
    group = { [groupName]: [] };
    services.push(group);
  }

  if (!Array.isArray(group[groupName])) {
    throw new Error(`Group '${groupName}' must contain an array`);
  }

  if (group[groupName].some((entry) => isPlainObject(entry) && Object.keys(entry)[0] === serviceName)) {
    return {
      isError: true,
      ...textContent(`Service '${serviceName}' already exists in group '${groupName}'.`),
    };
  }

  group[groupName].push({ [serviceName]: serviceConfig });
  const content = dumpYamlConfig("services.yaml", services);
  return textContent(
    JSON.stringify({ written: "services.yaml", added: { group: groupName, service: serviceName }, content }, null, 2),
  );
}

function addInfoWidget(args) {
  const disabled = ensureWriteEnabled();

View on GitHub (pinned to b6dca1ae03)

Solutions

  1. Open services.yaml and change the malformed group's value to a YAML sequence (e.g. `- Infra: []`).
  2. Use read_config_file / validate_config_file to inspect current shape before retrying add_service.
  3. Move any legitimate group-level metadata elsewhere — Homepage stores only the service list under the group key.
  4. Retry the add_service call once the structure is corrected.

Example fix

# before (services.yaml)
- Infra: {}

# after
- Infra:
    - Grafana:
        href: http://grafana:3000
Defensive patterns

Strategy: validation

Validate before calling

function findOrCreateGroup(services, groupName) {
  let g = services.find((e) => isPlainObject(e) && Object.keys(e)[0] === groupName);
  if (!g) { g = { [groupName]: [] }; services.push(g); }
  if (!Array.isArray(g[groupName])) throw new Error(`Group '${groupName}' must contain an array`);
  return g;
}

Type guard

function groupHasArray(entry, groupName) {
  return isPlainObject(entry) && Array.isArray(entry[groupName]);
}

Prevention

When it happens

Trigger: addService locates the group via `services.find(...)` and then checks `Array.isArray(group[groupName])`. It throws if, for example, services.yaml contains `- Infra: {}` or `- Infra: "some string"` instead of `- Infra: []`.

Common situations: Hand-edit produced `- Group: {}` or `- Group: null`; an older export wrote group metadata instead of a service list; partial migration from another dashboard format.

Related errors


AI-assisted analysis of gethomepage/homepage@b6dca1ae03 (2026-08-13). Data as JSON: /api/errors/2489167b15b30733. Report an issue: GitHub.