alibaba/spring-ai-alibaba · error · IOException

Failed to serialize metadata record {}

Error message

Failed to serialize metadata record {}

What it means

While normalizing a Java record used as a metadata value, SerializationHelper invokes Jackson property accessors/serializers and catches IllegalArgumentException. When record property access throws (e.g. a compact constructor or accessor invariant is violated, or a value fails Jackson coercion), it is rethrown as IOException naming the record class.

Source

Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/serializer/plain_text/jackson/SerializationHelper.java:213

					if (shouldInclude(provider, propertyInclusion, property, propertyValue)) {
						boolean hasAssignedSerializer = propertyWriter.isUnwrapping()
								|| !propertyWriter.getName().equals(property.getName())
								|| propertyWriter.getTypeSerializer() != null
								|| (propertyValue == null
										? propertyWriter.hasNullSerializer()
										: propertyWriter.hasSerializer());
						if (hasAssignedSerializer) {
							normalized.putAll(applyPropertyWriter(provider, propertyWriter, record));
						}
						else {
							normalized.put(property.getName(),
									normalizeMetadataValue(provider, propertyValue,
											propertyInclusion.getContentInclusion()));
						}
					}
				}
				catch (IllegalArgumentException ex) {
					throw new IOException("Failed to serialize metadata record " + record.getClass().getName(), ex);
				}
			}
			for (BeanPropertyWriter propertyWriter : remainingWriters) {
				normalized.putAll(applyPropertyWriter(provider, propertyWriter, record));
			}
			return normalized;
		}
		return value;
	}

	private static boolean requiresRecordNormalization(SerializerProvider provider, Record record,
			List<BeanPropertyDefinition> properties) throws IOException {
		for (BeanPropertyDefinition property : properties) {
			AnnotatedMember accessor = property.getAccessor();
			if (accessor == null) {
				continue;
			}
			try {

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Inspect the nested IllegalArgumentException cause to find which record property fails and fix the value before storing it in metadata
  2. Ensure all record components are of Jackson-serializable types (register JavaTimeModule etc. for dates, optionals)
  3. Make record accessors side-effect-free validation — validate in the compact constructor instead of failing during access
  4. Replace the problematic metadata value with a plain POJO/Map if the type keeps failing normalization

Example fix

// before: accessor throws on bad state
public record Range(int lo, int hi) { public int lo() { if (lo > hi) throw new IllegalArgumentException(); return lo; } }
// after: validate once in the compact constructor
public record Range(int lo, int hi) { public Range { if (lo > hi) throw new IllegalArgumentException("lo>hi"); } }
Defensive patterns

Strategy: try-catch

Validate before calling

try { for (var c : record.getClass().getRecordComponents()) c.getAccessor().invoke(value); } catch (Exception e) { /* exclude this value from metadata */ }

Type guard

boolean isMetadataSafe(Object v) {
    return v == null || v instanceof String || v instanceof Number || v instanceof Boolean || v instanceof Map || isSafelySerializableRecord(v);
}

Try / catch

try { metadata.put(key, recordValue); } catch (IOException e) { if (e.getMessage().startsWith("Failed to serialize metadata record")) { metadata.put(key, String.valueOf(recordValue)); } else throw e; }

Prevention

When it happens

Trigger: normalizeMetadataValue -> record property normalization: calling a record accessor or Jackson's serialization of a property raised IllegalArgumentException — e.g. accessor validates and rejects its stored state, or an incompatible nested container value.

Common situations: Records with validating compact constructors whose fields were deserialized/modified inconsistently; metadata values containing types Jackson cannot serialize with the configured ObjectMapper (unregistered modules, unsupported containers).

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/ca0cf2b4a383c056. Report an issue: GitHub.