can1357/oh-my-pi · error · RangeError

Format string contains an unescaped latin alphabet character

Error message

Format string contains an unescaped latin alphabet character `${character}`

What it means

The custom date-fns-v4-compatible formatter throws RangeError when the pattern contains an unescaped latin letter it does not recognize as a supported token. date-fns semantics require unknown letters to be quoted with single quotes so they are literal text.

Source

Thrown at packages/utils/src/dates.ts:138

					continue;
				}
				index++;
				break;
			}
			continue;
		}

		const rest = pattern.slice(index);
		const token = TOKENS.find(candidate => rest.startsWith(candidate));
		if (token) {
			result += tokenValue(date, token);
			index += token.length;
			continue;
		}

		const character = pattern[index++];
		if (/[A-Za-z]/.test(character)) {
			throw new RangeError(`Format string contains an unescaped latin alphabet character \`${character}\``);
		}
		result += character;
	}

	return result;
}

function plural(count: number, singular: string): string {
	return `${count} ${count === 1 ? singular : `${singular}s`}`;
}

function completedMonths(earlier: Date, later: Date): number {
	let months = (later.getFullYear() - earlier.getFullYear()) * 12 + later.getMonth() - earlier.getMonth();
	if (months === 0) return 0;

	const candidate = new Date(earlier);
	candidate.setDate(1);
	candidate.setFullYear(earlier.getFullYear(), earlier.getMonth() + months, 1);

View on GitHub (pinned to 9690622007)

Solutions

  1. Quote literal letters with single quotes: 'yyyy-MM-dd "(UTC)"' becomes "yyyy-MM-dd '(UTC)'" in date-fns style.
  2. Replace unsupported tokens with supported v4 tokens (see the formatter's token table).
  3. Wrap whole words in quotes: "yyyy 'at' HH:mm".
  4. Escape a literal single quote by doubling it inside a quoted section.

Example fix

// before
format(d, "yyyy-MM-dd (UTC)"); // RangeError: unescaped `U`
// after
format(d, "yyyy-MM-dd '(UTC)'");
Defensive patterns

Strategy: validation

Validate before calling

// reject unescaped latin letters outside quoted sections before formatting
if (/(^|')([^']*)[A-Za-z]/.test(pattern.replace(/'[^']*'/g, ""))) {
  throw new Error('Pattern contains unescaped letters; quote literals with single quotes');
}

Try / catch

try {
  return format(date, pattern);
} catch (err) {
  if (err instanceof RangeError && err.message.includes('unescaped latin alphabet')) {
    console.error(`Bad format string "${pattern}": ${err.message}`);
    return '';
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling format(date, pattern) with a pattern containing unsupported bare letters, e.g. 'yyyy-MM-dd (UTC)' where 'U','T','C' are unquoted, or patterns using tokens from other libraries (e.g. 'DD', 'hh a' variants) not in the supported set.

Common situations: Porting patterns from Moment.js/Luxon/day.js, embedding words like 'at' or 'UTC' directly in the pattern, or copying date-fns patterns that use tokens this shim does not implement.

Related errors


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