chenglou/pretext · error · Error

Could not determine Unicode version from DerivedBidiClass he

Error message

Could not determine Unicode version from DerivedBidiClass header

What it means

Thrown by buildPayload() in the bidi-data generator when it cannot find a header comment line matching '# DerivedBidiClass-<version>.txt' inside the bundled Unicode source file. The script depends on that exact header to extract the Unicode version string that gets stamped into the generated src/generated/bidi-data.ts. Without it, generation cannot proceed because the version is load-bearing metadata for the output.

Source

Thrown at scripts/generate-bidi-data.ts:93

  return { start, end }
}

function simplifyBidiType(raw: string): GeneratedBidiType {
  if (generatedTypeToCode.has(raw as GeneratedBidiType)) return raw as GeneratedBidiType
  if (bnProjectedTypes.has(raw)) return 'BN'

  const longName = longBidiNames.get(raw)
  if (longName !== undefined) return longName

  throw new Error(`Unsupported bidi class ${raw}`)
}

function buildPayload(sourceText: string): GeneratedBidiPayload {
  const sourceLines = sourceText.split(/\r?\n/)
  const versionLine = sourceLines.find(line => line.startsWith('# DerivedBidiClass-'))
  const versionMatch = versionLine?.match(/^# DerivedBidiClass-(.+)\.txt$/)
  if (versionMatch === null || versionMatch === undefined) {
    throw new Error('Could not determine Unicode version from DerivedBidiClass header')
  }
  const unicodeVersion = versionMatch[1]!

  const bidiCodes = new Uint8Array(0x110000)
  bidiCodes.fill(generatedTypeToCode.get('L')!)

  for (let i = 0; i < sourceLines.length; i++) {
    const rawLine = sourceLines[i]!
    let rangeText: string | null = null
    let typeText: string | null = null

    if (rawLine.startsWith('# @missing:')) {
      const missingMatch = rawLine.match(/^# @missing:\s*([0-9A-Fa-f]+(?:\.\.[0-9A-Fa-f]+)?)\s*;\s*([A-Za-z_]+)/)
      if (missingMatch === null) continue
      rangeText = missingMatch[1]!
      typeText = missingMatch[2]!
    } else {
      const line = rawLine.split('#', 1)[0]!.trim()

View on GitHub (pinned to ac49b09b7d)

Solutions

  1. Open scripts/unicode/DerivedBidiClass-17.0.0.txt and confirm the first comment line is exactly of the form `# DerivedBidiClass-17.0.0.txt`.
  2. If the file is missing or wrong, re-download the matching DerivedBidiClass.txt from the Unicode distribution for the version referenced by sourceFile in scripts/generate-bidi-data.ts:204 and place it at that path.
  3. If you intentionally changed the header format, update the regex at scripts/generate-bidi-data.ts:91 to match the new convention.
  4. If upgrading Unicode versions, also update the sourceFile path constant so it points at the new version's file.

Example fix

// before — header missing the trailing .txt
# DerivedBidiClass-17.0.0

// after
# DerivedBidiClass-17.0.0.txt
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync, existsSync } from 'node:fs'

function assertBidiSourceHeader(path: string): void {
  if (!existsSync(path)) throw new Error(`Missing Unicode source: ${path}`)
  const text = readFileSync(path, 'utf8')
  const hasHeader = text.split(/\r?\n/).some(l => /^# DerivedBidiClass-.+\.txt$/.test(l))
  if (!hasHeader) throw new Error(`DerivedBidiClass header not found in ${path}`)
}

assertBidiSourceHeader('scripts/unicode/DerivedBidiClass-17.0.0.txt')

Try / catch

try {
  await import('./generate-bidi-data.ts')
} catch (e) {
  if (e instanceof Error && e.message.includes('DerivedBidiClass header')) {
    console.error('Unicode source file is missing or its header changed. Re-fetch the matching DerivedBidiClass.txt and re-run.')
    process.exit(1)
  }
  throw e
}

Prevention

When it happens

Trigger: Running `bun run generate:bidi-data` when scripts/unicode/DerivedBidiClass-17.0.0.txt is missing, truncated, has had its comment header stripped, or has been replaced with a Unicode release whose header line no longer ends in `.txt`. Also triggered if the file is empty or only contains data rows with no leading comment.

Common situations: A maintainer upgrades to a new Unicode version and drops in a fresh DerivedBidiClass file that uses a slightly different header convention; or the source file got corrupted by a line-ending normalizer that mangled the leading `#`; or someone deleted the unicode/ directory.

Related errors


AI-assisted analysis of chenglou/pretext@ac49b09b7d (2026-08-12). Data as JSON: /api/errors/b7802de69ce74a52. Report an issue: GitHub.