bmad-code-org/BMAD-METHOD · error · TypeError
Async validation is not supported by @clack/prompts. Please
Error message
Async validation is not supported by @clack/prompts. Please use synchronous validation.
What it means
Thrown (as TypeError) inside the input-prompt wrapper when a question's validate callback returns a Promise. @clack/prompts' text() calls validate synchronously per keystroke; the wrapper detects a Promise return and converts it to a TypeError so the failure is loud instead of silently passing validation (the Promise would never be awaited).
Source
Thrown at tools/installer/prompts.js:701
// Handle conditional questions via 'when' property
if (when !== undefined) {
const shouldAsk = typeof when === 'function' ? await when(answers) : when;
if (!shouldAsk) continue;
}
let answer;
switch (type) {
case 'input': {
// Note: @clack/prompts doesn't support async validation, so validate must be sync
answer = await text({
message,
default: typeof defaultValue === 'function' ? defaultValue(answers) : defaultValue,
validate: validate
? (val) => {
const result = validate(val, answers);
if (result instanceof Promise) {
throw new TypeError('Async validation is not supported by @clack/prompts. Please use synchronous validation.');
}
return result === true ? undefined : result;
}
: undefined,
});
break;
}
case 'confirm': {
answer = await confirm({
message,
default: typeof defaultValue === 'function' ? defaultValue(answers) : defaultValue,
});
break;
}
case 'list': {
answer = await select({View on GitHub (pinned to b70486b9bd)
Solutions
- Make the validator synchronous: replace async with a sync function and use sync APIs (fs.pathExistsSync) or pre-computed state captured in closure.
- If the check is inherently async, perform it before the prompt and pass the result in, or validate after the prompt returns.
- Move expensive checks into a when predicate or a pre-prompt step that runs once.
Example fix
// before
// { type: 'input', name: 'path', message: 'Path:',
// validate: async (val) => (await fs.pathExists(val)) || 'Not found' }
//
// after
// { type: 'input', name: 'path', message: 'Path:',
// validate: (val) => fs.pathExistsSync(val) || 'Not found' } Defensive patterns
Strategy: validation
Validate before calling
function assertSyncValidators(questions) {
for (const q of questions) {
if (q.type === 'input' && typeof q.validate === 'function' && q.validate.constructor.name === 'AsyncFunction') {
throw new Error(`Validator for '${q.name}' is async; @clack/prompts requires sync.`);
}
}
}
assertSyncValidators(questions); Type guard
function isSyncValidator(fn) {
return typeof fn === 'function' && fn.constructor.name !== 'AsyncFunction';
} Try / catch
try {
answers = await getClack(questions);
} catch (e) {
if (/Async validation is not supported/.test(e.message)) {
// rewrite the offending validator to be sync and retry, or pre-validate inputs
} else { throw e; }
} Prevention
- Never declare prompt validate functions async when targeting @clack/prompts.
- Pre-compute async-only data before the prompt and close over it.
- Centralize validators in one module and lint for 'async' keyword on validate functions.
When it happens
Trigger: Defining a prompt question with type:'input' and a validate function declared async or returning a Promise — e.g. validate: async (val) => await fs.pathExists(val).
Common situations: Migrating from inquirer (which supports async validate) to @clack/prompts; reusing an async validator across prompt libraries; validating against the filesystem/network inside the prompt.
Related errors
- resolveChannel: pinned channel requires a pin value
- resolveChannel: unknown channel '${channel}'
- Obsolete implementation terminology found in deployable docu
- llms.txt must describe Build as canonical for both direct in
- --extra must be a JSON array of objects
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/8a83806dbabf8d80.
Report an issue: GitHub.