affaan-m/ECC · error · Error

${key} must be a non-empty string when provided

Error message

${key} must be a non-empty string when provided

What it means

readOptionalStringOption treats null/undefined/absent as 'not provided' (returns null), but if the key IS present it must be a non-empty trimmed string. Thrown when options[key] is a non-string type, an empty string, or whitespace-only.

Source

Thrown at scripts/lib/install-manifests.js:220

      description: `Install only the ${skillId} skill directory.`,
      modules: [moduleId],
      synthetic: true,
    });
    componentIds.add(componentId);
  }
}

function readOptionalStringOption(options, key) {
  if (
    !Object.prototype.hasOwnProperty.call(options, key)
    || options[key] === null
    || options[key] === undefined
  ) {
    return null;
  }

  if (typeof options[key] !== 'string' || options[key].trim() === '') {
    throw new Error(`${key} must be a non-empty string when provided`);
  }

  return options[key];
}

function readModuleTargetsOrThrow(module) {
  const moduleId = module && module.id ? module.id : '<unknown>';
  const targets = module && module.targets;

  if (!Array.isArray(targets)) {
    throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);
  }

  const normalizedTargets = targets.map(target => (
    typeof target === 'string' ? target.trim() : ''
  ));

  if (normalizedTargets.some(target => target.length === 0)) {

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Check the caller's option construction: only set the key when a real value exists.
  2. Coerce CLI input: skip the key when the flag value is empty (`--profile ''`).
  3. Trim and validate before passing: `if (v && typeof v === 'string') opts.key = v;`.
  4. If the value should legitimately be empty, omit the key entirely rather than passing ''.

Example fix

// before: readOptionalStringOption({ profile: '' }, 'profile')
// after:
const opts = {};
if (cliProfile && cliProfile.trim()) opts.profile = cliProfile;
readOptionalStringOption(opts, 'profile');
Defensive patterns

Strategy: validation

Validate before calling

function buildOptionalString(opts, key) {
  const v = opts[key];
  if (v === undefined || v === null) return null;
  if (typeof v !== 'string' || v.trim() === '') {
    throw new Error(`${key} must be a non-empty string when provided`);
  }
  return v;
}

Type guard

function isOptionalNonEmptyString(opts, key) {
  const v = opts[key];
  return v === undefined || v === null || (typeof v === 'string' && v.trim().length > 0);
}

Try / catch

try {
  profile = readOptionalStringOption(opts, 'profile');
} catch (err) {
  if (/must be a non-empty string when provided/.test(err.message)) {
    // omit the key instead of passing ''
  } else throw err;
}

Prevention

When it happens

Trigger: Passing an option object to a manifest API where a known key is set to '', ' ', a number, a boolean, or an object. The option is opt-in but when supplied it must be a real string value.

Common situations: Script forwards CLI flags without coercion (e.g. --profile= passed through as ''); env var unset but default empty string propagated; configuration file with `profile: ''` instead of omitting the key; number accidentally passed where a string id was expected.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/a854103f1d64822f. Report an issue: GitHub.