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

  1. Shorten the state path prefix: use a short repo-relative prefix instead of a deep absolute path
  2. Move the repo/state directory higher in the filesystem (shallower checkout path) to shrink rendered paths
  3. Reduce workspace/team name lengths that feed into the prefix
  4. 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

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


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/fc6b4115eccb7239. Report an issue: GitHub.