Yeachan-Heo/oh-my-codex · error · UltragoalError
Generated aggregate Codex objective exceeds the 4,000 charac
Error message
Generated aggregate Codex objective exceeds the 4,000 character goal limit.
What it means
aggregateCodexObjective builds a single objective string pointing at the ultragoal goals/ledger files, and throws if it exceeds 4,000 characters. Because the aggregate objective is essentially a fixed template plus prefixed state paths, this fires when the state-path prefix (repo layout / configured prefix) itself is long enough to push the rendered template over the limit — the goals content is referenced by path, not embedded.
Source
Thrown at src/ultragoal/artifacts.ts:734
function isResolvedStatus(status: UltragoalStatus): boolean {
return status === 'complete' || status === 'review_blocked';
}
function isScheduleEligibleGoal(goal: UltragoalItem): boolean {
return goal.steeringStatus !== 'superseded' && goal.steeringStatus !== 'blocked';
}
export const ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE = buildAggregateCodexObjective('');
function buildAggregateCodexObjective(statePathPrefix: string): string {
return `Complete the durable ultragoal plan in ${prefixedStatePath(statePathPrefix, ULTRAGOAL_GOALS)}, including later accepted/appended stories, under the original brief constraints; use ${prefixedStatePath(statePathPrefix, ULTRAGOAL_LEDGER)} as the audit trail.`;
}
function aggregateCodexObjective(statePathPrefix: string): string {
const objective = buildAggregateCodexObjective(statePathPrefix);
if (objective.length <= 4000) return objective;
throw new UltragoalError('Generated aggregate Codex objective exceeds the 4,000 character goal limit.');
}
function isLegacyEnumeratedAggregateObjective(objective: string | undefined): boolean {
if (!objective) return false;
return (
objective.startsWith(`Complete all ultragoal stories in ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}: `)
|| objective === `Complete all ultragoal stories listed in ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}. Use ${ULTRAGOAL_DIR}/${ULTRAGOAL_LEDGER} as the durable audit trail.`
);
}
function compatibleCodexObjectives(plan: UltragoalPlan): string[] {
return (plan.codexObjectiveAliases ?? [])
.filter((objective) => isLegacyEnumeratedAggregateObjective(objective)
|| objective === ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE);
}
function expectedCodexObjective(plan: UltragoalPlan, goal: UltragoalItem): string {
return codexGoalMode(plan) === 'aggregate'View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Shorten the state path prefix: use a short repo-relative prefix instead of a deep absolute path
- Move the repo/state directory higher in the filesystem (shallower checkout path) to shrink rendered paths
- Reduce workspace/team name lengths that feed into the prefix
- If you control the caller, pass an explicit short prefix argument rather than deriving one from cwd
Example fix
// before
aggregateCodexObjective('/var/lib/ci/workspaces/team-alpha-long-name/state/ultragoal'); // >4000 chars
// after
aggregateCodexObjective('.ultragoal'); // short repo-relative prefix Defensive patterns
Strategy: validation
Validate before calling
function prefixFitsAggregateObjective(statePathPrefix: string): boolean {
const templateOverhead = 512; // conservative fixed-template budget
return statePathPrefix.length + templateOverhead <= 4000;
} Try / catch
try {
const objective = aggregateCodexObjective(prefix);
} catch (e) {
if (e instanceof UltragoalError && /4,000 character goal limit/.test(e.message)) {
// shorten prefix to a repo-relative path and rebuild
} else throw e;
} Prevention
- Use short repo-relative state path prefixes, not deep absolute paths
- Keep workspace/team names short in CI
- Fail fast in config loading if the rendered prefix is unusually long
When it happens
Trigger: Calling aggregateCodexObjective(statePathPrefix) where prefixedStatePath renders paths whose combined length pushes the template past 4000 chars — i.e. a deeply nested repo or a very long configured statePathPrefix (absolute paths, long workspace names, nested monorepo directories).
Common situations: CI checkouts into very deep directories (/home/runner/work/<org>/<repo>/<long-name>/...); absolute rather than repo-relative state prefixes; long generated workspace/team names concatenated into the prefix; platform path-length limits compounding on Windows.
Related errors
- Blocked ultragoal checkpoint Codex snapshot is missing objec
- Invalid --codex-goal-mode; expected aggregate or per-story.
- Invalid ${label}: ${message}
- Missing --kind for structured ultragoal steer.
- Invalid --kind: ${raw}. Expected one of ${Array.from(STEERIN
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/fc6b4115eccb7239.
Report an issue: GitHub.