eyaltoledano/claude-task-master · error

INVALID_MODEL_ID

INVALID_MODEL_ID

Error message

Invalid model ID: ${modelId}. Must be a non-empty string.

What it means

setModel() requires a non-empty, non-whitespace string model ID. Before doing any config or provider lookup it validates typeof modelId === 'string' && modelId.trim() !== '', and returns this structured failure if not. It means the caller passed undefined/null/empty string (or a non-string) as the --model-id value.

Source

Thrown at scripts/modules/task-manager/models.js:420

	}

	// Validate role
	if (!['main', 'research', 'fallback'].includes(role)) {
		return {
			success: false,
			error: {
				code: 'INVALID_ROLE',
				message: `Invalid role: ${role}. Must be one of: main, research, fallback.`
			}
		};
	}

	// Validate model ID
	if (typeof modelId !== 'string' || modelId.trim() === '') {
		return {
			success: false,
			error: {
				code: 'INVALID_MODEL_ID',
				message: `Invalid model ID: ${modelId}. Must be a non-empty string.`
			}
		};
	}

	try {
		const availableModels = getAvailableModels(projectRoot);
		const currentConfig = getConfig(projectRoot);
		let determinedProvider = null; // Initialize provider
		let warningMessage = null;

		// Find the model data in internal list
		// If we have a provider hint, search for exact provider+model match
		// Otherwise, just search by model ID (will get first match)
		let modelData;
		if (providerHint) {
			// Search for model with specific provider
			modelData = availableModels.find(

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Re-run the command with an explicit non-empty model id, e.g. `task-master models --set-main --openrouter anthropic/claude-sonnet-4`.
  2. In scripts, check the value before calling: if (typeof modelId === 'string' && modelId.trim()) await setModel(modelId, 'main', root).
  3. If a shell/env variable supplies the id, verify it is exported and non-empty (`echo "$MODEL_ID"`) and add a default like ${MODEL_ID:-anthropic/claude-sonnet-4}.

Example fix

// before
await setModel(process.env.MODEL_ID, 'main', projectRoot); // undefined if env var missing
// after
const modelId = process.env.MODEL_ID?.trim();
if (!modelId) throw new Error('MODEL_ID env var must be set');
await setModel(modelId, 'main', projectRoot);
Defensive patterns

Strategy: validation

Validate before calling

function canSetModel(modelId) {
  return typeof modelId === 'string' && modelId.trim() !== '';
}
// before calling:
if (!canSetModel(modelId)) throw new Error('modelId must be a non-empty string');

Type guard

function isNonEmptyString(v) {
  return typeof v === 'string' && v.trim().length > 0;
}
if (isNonEmptyString(modelId)) {
  await setModel(modelId, 'main', projectRoot);
}

Try / catch

try {
  const res = await setModel(modelId, 'main', projectRoot);
  if (!res.success && res.error?.code === 'INVALID_MODEL_ID') {
    console.error('Provide a non-empty --model-id value, e.g. --openrouter vendor/model');
  }
} catch (e) {
  console.error('Unexpected setModel failure:', e.message);
}

Prevention

When it happens

Trigger: Calling setModel(modelId, role, projectRoot) with modelId = undefined, null, '', ' ', a number, or an object — e.g. the CLI flag --model-id was omitted or the flag was given without a value so the parsed argument is empty.

Common situations: Running `task-master models --set-main` without `--openrouter=<id>`/`--model-id` value; a shell variable holding the model id being unset/empty ($MODEL_ID with no default); scripting that interpolates a blank env var; typos where the value lands in the wrong flag.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/e011468a20a7f04a. Report an issue: GitHub.