alibaba/spring-ai-alibaba · error · IOException

Failed to apply serializer for metadata property

Error message

Failed to apply serializer for metadata property {}

What it means

applyPropertyWriter serializes one metadata record property through a TokenBuffer so it can be re-read into a normalized plain Map. If BeanPropertyWriter.serializeAsField throws for that property (custom serializer failure, accessor exception, unserializable value), the failure is wrapped as IOException naming the property.

Solutions

  1. Look at the cause chain to find the failing property and its custom serializer; fix or remove the custom serializer for metadata values
  2. Register required Jackson modules (JavaTimeModule, Jdk8Module) on the ObjectMapper used by SerializationHelper
  3. Keep metadata values as Jackson-friendly POJOs/Maps/records without cycles
  4. As a workaround, pre-convert the metadata value to a Map with objectMapper.convertValue before storing

Example fix

// before: metadata holds object with custom throwing serializer
metadata.put("span", new Span(Instant.now()));
// after: store a normalized Map
metadata.put("span", objectMapper.convertValue(new Span(Instant.now()), new TypeReference<Map<String,Object>>() {}));
Defensive patterns

Strategy: try-catch

Validate before calling

try { objectMapper.convertValue(value, new TypeReference<Map<String,Object>>() {}); return true; } catch (IllegalArgumentException e) { return false; }

Type guard

boolean isNormalizable(Object v) {
    try (TokenBuffer buf = new TokenBuffer(objectMapper, false)) { objectMapper.writeValue(buf, v); return true; } catch (Exception e) { return false; }
}

Try / catch

try { metadata.put(key, value); } catch (IOException e) { if (e.getMessage().startsWith("Failed to apply serializer for metadata property")) { metadata.put(key, value.toString()); } else throw e; }

Prevention

When it happens

Trigger: normalizeMetadataValue -> applyPropertyWriter: writer.serializeAsField(record, buffer, provider) throws for a specific property — e.g. a custom JsonSerializer throwing, infinite recursion, or accessor exception; also codec.readValue can fail if the buffered JSON does not map to Map<String,Object>.

Common situations: Custom Jackson serializers registered on metadata value types that throw or emit non-object JSON; properties of types requiring modules not registered (java.time, Optional); cyclic object graphs in metadata.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


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

Appendix: source

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

				return writer;
			}
			if (writer.getName().equals(property.getName())) {
				return writer;
			}
		}
		return null;
	}

	private static Map<String, Object> applyPropertyWriter(SerializerProvider provider,
			BeanPropertyWriter writer, Record record) throws IOException {
		ObjectCodec codec = provider.getGenerator().getCodec();
		try (TokenBuffer buffer = new TokenBuffer(codec, false)) {
			buffer.writeStartObject();
			try {
				writer.serializeAsField(record, buffer, provider);
			}
			catch (Exception ex) {
				throw new IOException("Failed to apply serializer for metadata property " + writer.getName(), ex);
			}
			buffer.writeEndObject();
			try (JsonParser parser = buffer.asParser(codec)) {
				return codec.readValue(parser, new TypeReference<>() {
				});
			}
		}
	}

	private static Object preserveMapType(SerializerProvider provider, Map<?, ?> original,
			Map<Object, Object> normalized, boolean changed) {
		if (!changed) {
			return original;
		}
		Map<Object, Object> copy = instantiateContainer(provider, original.getClass(), Map.class);
		if (copy == null) {
			return normalized;
		}

View on GitHub (pinned to f82da0b50f)