can1357/oh-my-pi · error · Error

Unknown changelog category: ${raw}

Error message

Unknown changelog category: ${raw}

What it means

changelogCategory() maps a raw category string (from model detail objects' changelog_category field) through CHANGELOG_CATEGORY_BY_NAME after trim+lowercase. Unrecognized values throw, because detail entries carry a changelog category that must be one of the fixed ChangelogCategory keys (Added/Changed/Fixed/Removed/Breaking Changes style) used in changelog rendering.

Source

Thrown at packages/coding-agent/src/commit/conventional/commit-types.ts:207

	for (const item of values) {
		if (typeof item === "string") {
			if (item) details.push({ text: item, userVisible: false });
			continue;
		}
		if (!isRecord(item) || item.text === null || item.text === undefined) continue;
		const text = String(item.text);
		if (!text) continue;
		const category =
			typeof item.changelog_category === "string" ? changelogCategory(item.changelog_category) : undefined;
		const userVisible = typeof item.user_visible === "boolean" ? item.user_visible : false;
		details.push({ text, changelogCategory: userVisible ? category : undefined, userVisible });
	}
	return details;
}

function changelogCategory(raw: string): ChangelogCategory {
	const category = CHANGELOG_CATEGORY_BY_NAME[raw.trim().toLowerCase()];
	if (!category) throw new Error(`Unknown changelog category: ${raw}`);
	return category;
}

function stringsFrom(value: unknown): string[] {
	if (value === null || value === undefined) return [];
	if (typeof value === "string") {
		const trimmed = value.trim();
		if (trimmed.startsWith("[")) {
			try {
				return stringsFrom(JSON.parse(trimmed));
			} catch {}
		}
		return value
			.split(/\r?\n/)
			.map(line => line.trim())
			.filter(Boolean);
	}
	if (Array.isArray(value)) return value.flatMap(stringsFrom);

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the error for the offending raw category and rename it to a configured one (added, changed, fixed, removed, breaking-changes)
  2. Re-run generation so the model emits categories from the documented list
  3. If the category is legitimately new, add it to CHANGELOG_CATEGORY_BY_NAME / the changelog resource
  4. Drop the changelog_category field (set user_visible false) if no category is needed

Example fix

// before
{ "text": "faster startup", "changelog_category": "Performance", "user_visible": true }
// after
{ "text": "faster startup", "changelog_category": "changed", "user_visible": true }
Defensive patterns

Strategy: validation

Validate before calling

const allowed = new Set(["added", "changed", "fixed", "removed", "breaking changes"]);
if (detail.changelog_category && !allowed.has(detail.changelog_category.trim().toLowerCase())) {
  throw new Error(`Bad category: ${detail.changelog_category}`);
}

Type guard

function isChangelogCategory(raw: string): raw is ChangelogCategory {
  return raw.trim().toLowerCase() in CHANGELOG_CATEGORY_BY_NAME;
}

Try / catch

try {
  const details = normalizeDetails(raw.details);
} catch (err) {
  if (err.message.startsWith("Unknown changelog category:")) {
    // drop or remap the offending detail's category and retry
  } else throw err;
}

Prevention

When it happens

Trigger: normalizeDetails() encounters a detail with changelog_category set to a string not in the map — e.g. "improvements", "features", "deprecated" (if not configured), typos, or plural/singular variants the map does not alias.

Common situations: LLM inventing near-miss category names in structured output; changelog vocabulary changed in the resource while cached model output still uses old names; hand-authored detail JSON with an ad-hoc category.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/10ab8d4a1a2926d7. Report an issue: GitHub.