affaan-m/ECC · error · Error

Claude scope and hook options require Claude to be selected.

Error message

Claude scope and hook options require Claude to be selected.

What it means

Claude-specific options (claudeScope, claudeHooks) are only meaningful when 'claude' is in the selected harnesses. normalizeGuidedInstallRequest checks includesClaude first and refuses the combination otherwise, because applying Claude scope/hook settings without installing Claude would silently no-op or, worse, mutate an unrelated harness's config. This is a fail-fast coherence check on the request shape.

Source

Thrown at scripts/lib/multi-harness-setup.js:29

const VALID_CLAUDE_SCOPES = new Set(['user', 'project', 'local']);
const VALID_CLAUDE_HOOKS = new Set(['off', 'minimal', 'standard', 'strict']);
const VALID_PROFILES = new Set(['minimal', 'core', 'developer', 'security', 'research', 'full']);

function catalogHelpers() {
  return require('./harness-capabilities');
}

function normalizeGuidedInstallRequest(input = {}) {
  const { normalizeHarnessSelection } = catalogHelpers();
  const harnesses = normalizeHarnessSelection(input.harnesses || []);
  if (harnesses.length === 0) {
    throw new Error('Choose at least one guided harness: Claude, Codex, or Kimi.');
  }

  const includesClaude = harnesses.includes('claude');
  const includesKimi = harnesses.includes('kimi');
  if (!includesClaude && (input.claudeScope !== undefined || input.claudeHooks !== undefined)) {
    throw new Error('Claude scope and hook options require Claude to be selected.');
  }
  if (!includesKimi && input.profile !== undefined) {
    throw new Error('The managed install profile requires Kimi to be selected.');
  }

  const claudeScope = includesClaude ? (input.claudeScope || 'user') : undefined;
  const claudeHooks = includesClaude ? (input.claudeHooks || 'standard') : undefined;
  const profile = includesKimi ? (input.profile || 'core') : undefined;
  if (claudeScope && !VALID_CLAUDE_SCOPES.has(claudeScope)) {
    throw new Error(`Invalid Claude scope: ${claudeScope}`);
  }
  if (claudeHooks && !VALID_CLAUDE_HOOKS.has(claudeHooks)) {
    throw new Error(`Invalid Claude hooks preference: ${claudeHooks}`);
  }
  if (profile && !VALID_PROFILES.has(profile)) {
    throw new Error(`Invalid Kimi install profile: ${profile}`);
  }

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Either add 'claude' to harnesses, or remove the claudeScope/claudeHooks fields from the input.
  2. When building the request programmatically, only set claudeScope/claudeHooks conditionally: if (harnesses.includes('claude')) request.claudeScope = scope.
  3. Audit the calling code for stale defaults that always populate these fields.
  4. Prefer omitting the key entirely over setting it to undefined.

Example fix

// before
normalizeGuidedInstallRequest({ harnesses: ['codex'], claudeScope: 'user' }); // throws
// after (option A: drop the option)
normalizeGuidedInstallRequest({ harnesses: ['codex'] });
// after (option B: add claude)
normalizeGuidedInstallRequest({ harnesses: ['codex', 'claude'], claudeScope: 'user' });
Defensive patterns

Strategy: validation

Validate before calling

function buildClaudeOptions(input = {}) {
  const harnesses = input.harnesses || [];
  const opts = { harnesses };
  if (harnesses.includes('claude')) {
    if (input.claudeScope !== undefined) opts.claudeScope = input.claudeScope;
    if (input.claudeHooks !== undefined) opts.claudeHooks = input.claudeHooks;
  }
  return opts;
}
// use buildClaudeOptions before normalizeGuidedInstallRequest

Try / catch

try { normalizeGuidedInstallRequest(input); }
catch (error) {
  if (/Claude scope and hook options require Claude/i.test(error.message)) {
    console.error('Either add \'claude\' to harnesses or drop claudeScope/claudeHooks.');
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling normalizeGuidedInstallRequest with input.claudeScope or input.claudeHooks set to any value (including undefined-explicit) while input.harnesses does not include 'claude'. Common when a caller threads through stale defaults or builds the request from a template that always sets claudeScope.

Common situations: A UI form that always submits claudeScope/claudeHooks fields even when Claude is unchecked; copy-pasted request objects from a prior Claude install; a wrapper that sets defaults unconditionally; passing { claudeHooks: undefined } explicitly (the check uses !== undefined, so explicit undefined still trips it in some code paths — but null is fine).

Related errors


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