eyaltoledano/claude-task-master · error · Error

Custom executor not yet implemented

Error message

Custom executor not yet implemented

What it means

Plain Error thrown by ExecutorFactory.create when options.type is 'custom'. Like the shell case, the custom executor is a placeholder branch in the factory switch and always throws. It indicates the requested executor kind exists as an enum-like option but has no implementation yet.

Source

Thrown at packages/tm-core/src/modules/execution/executors/executor-factory.ts:28

	private static logger = getLogger('ExecutorFactory');

	/**
	 * Create an executor based on the provided options
	 */
	static create(options: ExecutorOptions): ITaskExecutor {
		this.logger.debug(`Creating executor of type: ${options.type}`);

		switch (options.type) {
			case 'claude':
				return new ClaudeExecutor(options.projectRoot, options.config);

			case 'shell':
				// Placeholder for shell executor
				throw new Error('Shell executor not yet implemented');

			case 'custom':
				// Placeholder for custom executor
				throw new Error('Custom executor not yet implemented');

			default:
				throw new Error(`Unknown executor type: ${options.type}`);
		}
	}

	/**
	 * Get the default executor type based on available tools
	 */
	static async getDefaultExecutor(
		projectRoot: string
	): Promise<ExecutorType | null> {
		// Check for Claude first
		const claudeExecutor = new ClaudeExecutor(projectRoot);
		if (await claudeExecutor.isAvailable()) {
			this.logger.info('Claude CLI detected as default executor');
			return 'claude';
		}

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Use type: 'claude' (the implemented executor) or omit type to use the default
  2. Implement the Executor interface yourself and instantiate it directly instead of going through the factory
  3. Upgrade @tm/core when a custom executor is released
  4. Pre-validate the executor type in your own code and fall back to a supported value
  5. Map 'custom' to an implemented executor in your config layer

Example fix

// before
const exec = ExecutorFactory.create({ type: 'custom', projectRoot });
// after
const exec = ExecutorFactory.create({ type: 'claude', projectRoot });
Defensive patterns

Strategy: validation

Validate before calling

type SupportedExecutor = 'claude';
function assertImplemented(t: string): asserts t is SupportedExecutor {
  if (t !== 'claude') throw new Error(`Executor '${t}' not implemented; use 'claude'`);
}

Type guard

const isImplementedExecutor = (t: unknown): t is 'claude' =>
  typeof t === 'string' && t === 'claude';

Try / catch

try {
  executor = ExecutorFactory.create({ type: 'custom', projectRoot });
} catch (e) {
  if (e.message.includes('not yet implemented')) {
    executor = ExecutorFactory.create({ type: 'claude', projectRoot });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling ExecutorFactory.create({ type: 'custom', projectRoot }) — unconditional throw for this exact type value.

Common situations: A config or API consumer selecting 'custom' to plug in their own runner; copying an options object with type from an unvalidated source; experimentation with the factory's supported types.

Related errors


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