ramensoftware/windhawk · error

More than one settings key

Error message

More than one settings key

What it means

parseSettingItem validates that each settings item object has exactly one non-meta key (the actual setting name); keys starting with '$' are metadata and excluded. If an item object carries two or more real setting keys, the shape is ambiguous and this Error is thrown so the caller knows the settings entry is malformed.

Solutions

  1. Inspect the settings item object at the failing location and split it so each object contains exactly one non-$ key.
  2. Fix the mod's metadata (the [Mg] settings JSON) at the source so it is not committed with multiple keys per item.
  3. If extra data is intentional, prefix those keys with '$' so they are treated as metadata instead of setting keys.

Example fix

// before
{ "$maxValue": 100, "FontSize": 14, "Theme": "dark" }
// after
{ "$maxValue": 100, "FontSize": 14 }
{ "$maxValue": 3, "Theme": "dark" }
Defensive patterns

Strategy: validation

Validate before calling

function isValidSettingItem(value) {
  const keys = Object.keys(value).filter((k) => !k.startsWith('$'));
  return keys.length === 1;
}
if (!isValidSettingItem(item)) throw new Error('Settings item must have exactly one key');

Type guard

const isSettingItem = (v: Record<string, unknown>): v is { [k: string]: unknown } =>
  Object.keys(v).filter((k) => !k.startsWith('$')).length === 1;

Try / catch

try {
  const parsed = parseSettingItem(item);
} catch (e) {
  if (e.message.includes('settings key')) {
    console.warn('Malformed settings item, skipping:', item);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling parseSettingItem with an object like { "Setting1": {...}, "Setting2": {...} } (more than one key not prefixed with '$'), e.g. a mod's [Mg] metadata JSON that accidentally merged two settings into one object.

Common situations: Hand-edited or corrupted mod metadata files; authors copy-pasting a settings block and forgetting to split two settings into separate objects; automated tooling generating merged settings entries.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.


AI-assisted analysis of ramensoftware/windhawk@61d99ed8e1 (2026-09-12). Data as JSON: /api/errors/071193135c9c5af2. Report an issue: GitHub.

Appendix: source

Thrown at src/windhawk-frontend/apps/windhawk-frontend/src/app/panel/mod-details/ModDetails.Website.tsx:108

    }

    const parseSettings = (
      settingsArray: Record<string, unknown>[]
    ): InitialSettings => {
      return settingsArray.map(parseSettingItem);
    };

    const parseSettingItem = (
      value: Record<string, unknown>
    ): InitialSettingItem => {
      // Find the actual setting key (not starting with $)
      const actualParameters = Object.keys(value).filter(
        (x) => !x.startsWith('$')
      );
      if (actualParameters.length === 0) {
        throw new Error('Missing settings key');
      } else if (actualParameters.length > 1) {
        throw new Error('More than one settings key');
      }

      const actualParameter = actualParameters[0];
      const metaParameters = Object.keys(value).filter((x) =>
        x.startsWith('$')
      );

      // Group meta parameters by their base name (name, description, options)
      const metaGroups: Record<
        string,
        Array<{ language: string | null; value: unknown }>
      > = {};

      for (const paramWithPrefix of metaParameters) {
        const param = paramWithPrefix.slice(1); // remove '$'
        const paramParts = param.split(':');
        const baseName = paramParts[0];
        const lang = paramParts[1] ?? null;

View on GitHub (pinned to 61d99ed8e1)