pbakaus/impeccable · error
preflight returned no scaffold metadata
Error message
preflight returned no scaffold metadata
What it means
runGenerationPreflight() (skill/scripts/live/generation-preflight.mjs) spawns `node live-insert.mjs|live-wrap.mjs --id ... --defer-source-write ...` with a 15s timeout to scaffold a generate event before the agent takes over. The helper's stdout is expected to end with a JSON metadata line, which is then JSON.parsed and its sourceFile/file cached by target signature. This error means the subprocess exited 0 but produced no non-empty stdout line at all — the metadata line is simply absent.
Solutions
- Re-run the helper manually with the same arguments (visible in server logs) and inspect stdout — no trailing JSON line confirms the mismatch
- Make scriptsDir contain the same skill version as the server: refresh/reinstall the skill or rebuild in the repo
- If the helper prints a not-found/quiet result, fix the locator (element id/classes/tag) so the scaffold actually resolves
- Keep server and helper scripts updated together — the preflight contract (exit 0 + last-line JSON) is version-coupled
Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
import path from 'node:path';
// Before relying on preflight, confirm the helper this server version expects
// is the one actually present in scriptsDir.
for (const helper of ['live-insert.mjs', 'live-wrap.mjs']) {
const p = path.join(scriptsDir, helper);
if (!fs.existsSync(p)) throw new Error(`helper missing: ${p}`);
} Try / catch
const result = await runGenerationPreflight(event, { cwd, scriptsDir });
if (!result.ok && result.reason?.includes('preflight returned no scaffold metadata')) {
// Version/install mismatch: run the printed helper args manually,
// then refresh the skill so server and helpers share one version.
logRecoveryHint(result.reason);
} Prevention
- Keep live-server.mjs and live-insert/live-wrap.mjs from the same skill version — the stdout metadata contract is version-coupled
- After partial updates, smoke-test one generate event before a long session
- When embedding, point scriptsDir at the complete scripts tree of one release
When it happens
Trigger: An older live-insert.mjs/live-wrap.mjs in scriptsDir that doesn't implement the trailing metadata line (version mismatch with the server); a quiet not-found code path that exits successfully without printing; output swallowed by a wrapper; stdout redirected inside the helper.
Common situations: Partial skill updates leaving new live-server.mjs paired with stale helper scripts; custom installs where scriptsDir mixes versions; helper behavior changing across releases while the cached signature path expects the new format.
Related errors
- {}
- impeccable: verb ' ' is not implemented yet
- No live copy-edit AI runner is available.
- --target requires a path value
- Unsupported live copy-edit AI runner
AI-assisted analysis of pbakaus/impeccable@f88b2837a7 (2026-08-18).
Data as JSON: /api/errors/6902ef1e441bb932.
Report an issue: GitHub.
Appendix: source
Thrown at skill/scripts/live/generation-preflight.mjs:92
scriptsDir,
execFileImpl = execFileAsync,
timeoutMs = PREFLIGHT_TIMEOUT_MS,
cache = sourceResolutionCache,
} = {}) {
const command = buildGenerationPreflight(event, scriptsDir, { cache });
if (!command) {
return { ok: false, skipped: true, reason: 'insufficient_locator' };
}
const startedAt = performance.now();
try {
const { stdout } = await execFileImpl(process.execPath, command.args, {
cwd,
encoding: 'utf-8',
timeout: timeoutMs,
});
const line = String(stdout).trim().split('\n').filter(Boolean).pop();
if (!line) throw new Error('preflight returned no scaffold metadata');
const scaffold = JSON.parse(line);
// Cache the resolved SOURCE file (route source, not the svelte manifest) so
// the next generate on this target skips the tree search.
const resolvedSource = scaffold.sourceFile || scaffold.file;
if (cache && command.signature && typeof resolvedSource === 'string') {
cache.set(command.signature, resolvedSource);
}
return {
ok: true,
mode: command.mode,
durationMs: performance.now() - startedAt,
scaffold,
};
} catch (error) {
// Evict a stale/failed resolution so the next attempt does a full search
// (the element may have moved out of the previously cached file).
if (cache && command.signature) cache.delete(command.signature);
return {View on GitHub (pinned to f88b2837a7)