Spring-Data-MongoDB
conversion-error
version-upgrade-issues
custom-converter
troubleshooting

Spring-Data-MongoDB Failed to convert from type after upgrade to 2.0.7 with custom converter

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

A Spring Data MongoDB upgrade can expose conversion problems that were previously hidden by looser mapping behavior. When a custom converter suddenly starts failing with a message like "failed to convert from type," the issue is usually not MongoDB itself. It is typically one of three things: the converter is not registered, the converter direction is ambiguous, or the actual BSON shape in the collection no longer matches what the Java code expects.

Make Converter Direction Explicit

A custom converter should clearly state whether it is for reading or writing. That removes ambiguity in the conversion system.

java
1import org.springframework.core.convert.converter.Converter;
2import org.springframework.data.convert.ReadingConverter;
3import org.springframework.data.convert.WritingConverter;
4
5@ReadingConverter
6public class StringToMoneyConverter implements Converter<String, Money> {
7    @Override
8    public Money convert(String source) {
9        return Money.parse(source);
10    }
11}
12
13@WritingConverter
14public class MoneyToStringConverter implements Converter<Money, String> {
15    @Override
16    public String convert(Money source) {
17        return source.toString();
18    }
19}

Without @ReadingConverter and @WritingConverter, a converter can be applied more broadly than intended and cause surprising type failures.

Register Converters Explicitly

Do not assume the converter will be picked up automatically in exactly the way you want. Register it through MongoCustomConversions.

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
4
5import java.util.List;
6
7@Configuration
8public class MongoConfig {
9
10    @Bean
11    MongoCustomConversions mongoCustomConversions() {
12        return new MongoCustomConversions(
13            List.of(new StringToMoneyConverter(), new MoneyToStringConverter())
14        );
15    }
16}

This makes the mapping behavior explicit and much easier to reason about during upgrades.

Verify the Actual Stored Data Shape

Even correct converter code will fail if the stored MongoDB field is not the type your converter expects. For example, a converter from String to Money cannot help if older documents now contain a nested object instead of a string.

That is why you should inspect real documents before changing more Java code.

Questions to answer:

  • Is the field actually a string, document, array, or null?
  • Do old and new formats coexist in the same collection?
  • Are some records missing the field entirely?

Upgrade failures often come from the gap between code assumptions and historical production data.

Add a Round-Trip Integration Test

A unit test on the converter alone is not enough. You want a repository-level test that exercises Spring Data's actual mapping layer.

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
4
5import static org.assertj.core.api.Assertions.assertThat;
6
7@DataMongoTest
8class MoneyConversionTest {
9
10    @Autowired
11    PaymentRepository repository;
12
13    @Test
14    void writesAndReadsMoney() {
15        Payment saved = repository.save(new Payment(null, Money.parse("USD:12.34")));
16        Payment loaded = repository.findById(saved.id()).orElseThrow();
17
18        assertThat(loaded.amount()).isEqualTo(saved.amount());
19    }
20}

This catches the real failure mode: not just whether the converter compiles, but whether Spring Data can actually persist and read the entity after the upgrade.

Plan for Mixed Historical Data

If production contains old and new document formats, the safest path is often a staged migration:

  1. deploy a read-compatible converter that can understand both formats
  2. keep writing the canonical format
  3. backfill or migrate old documents
  4. remove temporary compatibility logic later

That approach is safer than trying to flip the entire collection format in one deploy.

Common Pitfalls

  • Writing a converter but never registering it in MongoCustomConversions.
  • Providing only one converter direction when the domain type is both read and written.
  • Assuming the collection data shape matches the new code without checking.
  • Making converters too generic so they intercept unrelated mappings.
  • Testing only the converter class instead of the full repository mapping path.

Summary

  • Upgrade-time conversion failures usually come from registration or data-shape mismatches.
  • Mark converters explicitly as reading or writing.
  • Register them deliberately through MongoCustomConversions.
  • Inspect the real BSON values in the database, not just the Java types.
  • Protect upgrades with integration tests and, if necessary, staged data migration.

Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design