apache/pulsar · error · MetadataFormatException

Rejected legacy package metadata:

Error message

Rejected legacy package metadata: 

What it means

This is the catch-all wrapper in readLegacy: any exception thrown while reading legacy Java-serialized metadata (InvalidClassException, ClassNotFoundException, StreamCorruptedException, EOFException, etc.) is rethrown as MetadataFormatException with the original message appended. It signals the stored bytes could not be safely deserialized as legacy package metadata.

Source

Thrown at pulsar-package-management/core/src/main/java/org/apache/pulsar/packages/management/core/common/PackageMetadataUtil.java:119

    private static PackageMetadata readLegacy(byte[] bytes) throws MetadataFormatException {
        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
            ois.setObjectInputFilter(LEGACY_FILTER);
            Object o = ois.readObject();
            if (!(o instanceof PackageMetadata)) {
                throw new MetadataFormatException("Unexpected metadata type: "
                        + (o == null ? "null" : o.getClass().getName()));
            }
            if (LEGACY_READ_WARNED.compareAndSet(false, true)) {
                log.warn("Read a package metadata entry in the legacy Java serialization format. "
                        + "Re-upload packages or call updateMeta to migrate them to JSON, then disable "
                        + "packagesManagementAllowLegacyJavaSerialization.");
            }
            return (PackageMetadata) o;
        } catch (MetadataFormatException e) {
            throw e;
        } catch (Exception e) {
            throw new MetadataFormatException("Rejected legacy package metadata: " + e.getMessage());
        }
    }

    private static int indexOfFirstNonWhitespace(byte[] bytes) {
        for (int i = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            if (b != ' ' && b != '\t' && b != '\n' && b != '\r') {
                return i;
            }
        }
        return -1;
    }

    // Source-compatible overloads for callers (including external integrations) that haven't
    // been updated to the explicit-flag form. Defaults track the production defaults.
    @Deprecated
    public static byte[] toBytes(PackageMetadata packageMetadata) {
        return toBytes(packageMetadata, true);

View on GitHub (pinned to 820761864e)

Solutions

  1. Re-upload the package or call updateMeta to migrate the entry to JSON format, then disable packagesManagementAllowLegacyJavaSerialization.
  2. Inspect the wrapped message in the MetadataFormatException to identify the underlying cause (class-not-found vs corrupted stream vs filter rejection).
  3. If the class shape changed across versions, migrate metadata using the same Pulsar version that wrote it.
  4. Delete and recreate the affected package metadata entry.

Example fix

// before: relying on legacy serialization
conf.setPackagesManagementAllowLegacyJavaSerialization(true);
// after: migrate and disable legacy support
metadataService.updateMetadata(packageName, PackageMetadataUtil.toBytes(newMetadata));
conf.setPackagesManagementAllowLegacyJavaSerialization(false);
Defensive patterns

Strategy: try-catch

Try / catch

try {
    PackageMetadata m = PackageMetadataUtil.fromBytes(bytes);
} catch (MetadataFormatException e) {
    Throwable cause = e.getCause();
    log.warn("Legacy metadata rejected: {} (cause: {})", e.getMessage(), cause, e);
    // treat as corrupt entry: re-upload or delete
}

Prevention

When it happens

Trigger: fromBytes() is given bytes in the legacy format that fail deserialization: stream corrupted, class not found on classpath, class version mismatch, or the ObjectInputFilter rejected a field/class (e.g. a nested non-whitelisted object inside PackageMetadata).

Common situations: Pulsar upgrade changed the PackageMetadata class shape (serialVersionUID mismatch); metadata blob truncated or corrupted on disk/storage backend; security filter (LEGACY_FILTER) rejects classes referenced in the serialized graph.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/e47d2b67aded3c95. Report an issue: GitHub.