nodejs/node · error

U_INVALID_FORMAT_ERROR

U_INVALID_FORMAT_ERROR

Error message

invalid format of pool bundle file %s

What it means

After swapping, genrb casts the buffer to a DataHeader and checks header->info.formatVersion[0]. Pool bundles require formatVersion >= 2 because the pool keys/indexes layout was introduced with formatVersion 2. A pool.res with formatVersion[0] < 2 is rejected with U_INVALID_FORMAT_ERROR. This is a stricter, structural follow-up to the format checks done on the command line.

Source

Thrown at deps/icu-small/source/tools/genrb/genrb.cpp:416

         * a well-formed .res file.
         */
        ds = udata_openSwapperForInputData(poolBundle.fBytes, bytesRead,
                                           U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &status);
        if (U_FAILURE(status)) {
            fprintf(stderr, "udata_openSwapperForInputData(pool bundle %s) failed: %s\n",
                    poolFileName.data(), u_errorName(status));
            return status;
        }
        ures_swap(ds, poolBundle.fBytes, bytesRead, poolBundle.fBytes, &status);
        udata_closeSwapper(ds);
        if (U_FAILURE(status)) {
            fprintf(stderr, "ures_swap(pool bundle %s) failed: %s\n",
                    poolFileName.data(), u_errorName(status));
            return status;
        }
        header = reinterpret_cast<const DataHeader*>(poolBundle.fBytes);
        if (header->info.formatVersion[0] < 2) {
            fprintf(stderr, "invalid format of pool bundle file %s\n", poolFileName.data());
            return U_INVALID_FORMAT_ERROR;
        }
        const int32_t* pRoot = reinterpret_cast<const int32_t*>(
                reinterpret_cast<const char*>(header) + header->dataHeader.headerSize);
        poolBundle.fIndexes = pRoot + 1;
        indexLength = poolBundle.fIndexes[URES_INDEX_LENGTH] & 0xff;
        if (indexLength <= URES_INDEX_POOL_CHECKSUM) {
            fprintf(stderr, "insufficient indexes[] in pool bundle file %s\n", poolFileName.data());
            return U_INVALID_FORMAT_ERROR;
        }
        int32_t keysBottom = 1 + indexLength;
        int32_t keysTop = poolBundle.fIndexes[URES_INDEX_KEYS_TOP];
        poolBundle.fKeys = reinterpret_cast<const char*>(pRoot + keysBottom);
        poolBundle.fKeysLength = (keysTop - keysBottom) * 4;
        poolBundle.fChecksum = poolBundle.fIndexes[URES_INDEX_POOL_CHECKSUM];

        for (i = 0; i < poolBundle.fKeysLength; ++i) {
            if (poolBundle.fKeys[i] == 0) {

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Regenerate pool.res with a current genrb at formatVersion 2 or 3 (the default).
  2. Discard legacy pool.res files when upgrading ICU major versions.
  3. Run `icupkg -l pool.res` to inspect its formatVersion before use.
Defensive patterns

Strategy: validation

Validate before calling

# Reject a legacy formatVersion-1 pool.res up front
# (icupkg -l output or a small od inspection can reveal the formatVersion byte)
fv_byte=$(od -An -tu1 -j "$((0x18))" -N1 "$POOL_DIR/pool.res" 2>/dev/null | tr -d ' ')
if [ -n "$fv_byte" ] && [ "$fv_byte" -lt 2 ]; then
  echo "ERROR: pool.res formatVersion=$fv_byte, need >= 2" >&2; exit 2
fi

Try / catch

genrb --usePoolBundle "$POOL_DIR" "$@" 2>err.log || {
  grep -q 'invalid format of pool bundle file' err.log && \
    echo "pool.res too old; regenerate with current genrb" >&2
  exit 1
}

Prevention

When it happens

Trigger: Using a pool.res that was generated with --formatVersion 1 (or by an old genrb that only wrote formatVersion 1). The command-line guard (error 761) prevents producing such a combination, but a hand-carried or legacy pool.res can still hit this.

Common situations: Reusing a checked-in pool.res from an older ICU; cross-version data sharing; manually editing or down-converting pool.res.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/c494c75548eebcc8. Report an issue: GitHub.