Yeachan-Heo/oh-my-codex · error · GoalWorkflowError
Missing goal workflow objective.
Error message
Missing goal workflow objective.
What it means
GoalWorkflowError thrown by createGoalWorkflowRun when options.objective is empty after trimming. The objective is the required human-readable goal of the run; without it the workflow has nothing to drive slug generation and status tracking, so creation is refused before any files are written.
Source
Thrown at src/goal-workflows/artifacts.ts:128
return join(goalWorkflowDir(cwd, workflow, slug), GOAL_WORKFLOW_STATUS);
}
export function goalWorkflowLedgerPath(cwd: string, workflow: string, slug: string): string {
return join(goalWorkflowDir(cwd, workflow, slug), GOAL_WORKFLOW_LEDGER);
}
export async function appendGoalWorkflowLedger(cwd: string, run: GoalWorkflowRun, entry: GoalWorkflowLedgerEntry): Promise<void> {
await mkdir(join(cwd, run.artifactDir), { recursive: true });
await appendFile(join(cwd, run.ledgerPath), `${JSON.stringify(entry)}\n`);
}
async function writeRun(cwd: string, run: GoalWorkflowRun): Promise<void> {
await mkdir(join(cwd, run.artifactDir), { recursive: true });
await writeFile(join(cwd, run.statusPath), `${JSON.stringify(run, null, 2)}\n`);
}
export async function createGoalWorkflowRun(cwd: string, options: CreateGoalWorkflowRunOptions): Promise<GoalWorkflowRun> {
if (!options.objective.trim()) throw new GoalWorkflowError('Missing goal workflow objective.');
const workflow = normalizeGoalWorkflowSegment(options.workflow);
const slug = normalizeGoalWorkflowSegment(options.slug ?? slugFromObjective(options.objective), 'goal-workflow');
const statusPath = goalWorkflowStatusPath(cwd, workflow, slug);
if (!options.force && existsSync(statusPath)) {
throw new GoalWorkflowError(`Refusing to overwrite existing ${repoRelative(cwd, statusPath)}; pass force to recreate it.`);
}
const now = iso(options.now);
const artifactDir = repoRelative(cwd, goalWorkflowDir(cwd, workflow, slug));
const run: GoalWorkflowRun = {
version: 1,
workflow,
slug,
objective: options.objective.trim(),
status: 'pending',
createdAt: now,
updatedAt: now,
artifactDir,View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Validate the objective is non-empty after trim before calling createGoalWorkflowRun.
- If the objective comes from config, fail fast with a descriptive error naming the missing key.
- Default or prompt for the objective in the calling layer when it would be blank.
- Add a form/schema-level required constraint so blank objectives never reach the API.
Example fix
// before
await createGoalWorkflowRun(cwd, { objective: cfg.objective ?? '' });
// after
const objective = (cfg.objective ?? '').trim();
if (!objective) throw new Error('config.objective is required to create a goal workflow run');
await createGoalWorkflowRun(cwd, { objective }); Defensive patterns
Strategy: validation
Validate before calling
const objective = options.objective?.trim();
if (!objective) throw new Error('objective is required');
await createGoalWorkflowRun(cwd, { ...options, objective }); Type guard
function isValidObjective(v: unknown): v is string {
return typeof v === 'string' && v.trim().length > 0;
} Try / catch
try { await createGoalWorkflowRun(cwd, options); }
catch (e) { if (e instanceof GoalWorkflowError && e.message.includes('objective')) {/* prompt user for objective */} else throw e; } Prevention
- Mark objective required in your form/config schema.
- Fail fast on blank template variables before calling the API.
- Unit-test the blank-objective path in your wrapper.
When it happens
Trigger: Calling createGoalWorkflowRun with objective: '', ' ', or a variable that is undefined/null coerced to whitespace; CLI/form layer submitting an untouched objective field; objective loaded from an empty config key.
Common situations: Automation derives the objective from a template variable that wasn't filled in; YAML/JSON config has an empty objective key; whitespace-only input accepted by a UI text field; test fixture left blank.
Related errors
- missing_prompt
- sendToWorker: text must be non-empty
- invalid auth slot path
- Autoresearch goal ${mission.slug} cannot complete until prof
- autoresearch candidate artifact notes must be a string array
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/56787a2fb832d013.
Report an issue: GitHub.