{"id":"6e308b6cb97ebd36","repo":"junit-team/junit5","slug":"no-built-in-converter-for-source-type-java-lang-st","errorCode":null,"errorMessage":"No built-in converter for source type java.lang.String and target type ${targetType.getTypeName()}","messagePattern":"No built-in converter for source type java\\.lang\\.String and target type (.+?)","errorType":"exception","errorClass":"ConversionException","httpStatus":null,"severity":"error","filePath":"junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java","lineNumber":140,"sourceCode":"\t\t\tcandidate -> candidate.canConvertTo(targetTypeToUse)).findFirst();\n\t\tif (converter.isPresent()) {\n\t\t\ttry {\n\t\t\t\tClassLoader classLoaderToUse = classLoader != null ? classLoader\n\t\t\t\t\t\t: ClassLoaderUtils.getDefaultClassLoader();\n\t\t\t\treturn (T) converter.get().convert(source, targetTypeToUse, classLoaderToUse);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tif (ex instanceof ConversionException conversionException) {\n\t\t\t\t\t// simply rethrow it\n\t\t\t\t\tthrow conversionException;\n\t\t\t\t}\n\t\t\t\t// else\n\t\t\t\tthrow new ConversionException(\n\t\t\t\t\t\"Failed to convert String \\\"%s\\\" to type %s\".formatted(source, targetType.getTypeName()), ex);\n\t\t\t}\n\t\t}\n\n\t\tthrow new ConversionException(\n\t\t\t\"No built-in converter for source type java.lang.String and target type \" + targetType.getTypeName());\n\t}\n\n\tprivate static Class<?> toWrapperType(Class<?> targetType) {\n\t\tClass<?> wrapperType = getWrapperType(targetType);\n\t\treturn wrapperType != null ? wrapperType : targetType;\n\t}\n\n}\n","sourceCodeStart":122,"sourceCodeEnd":150,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java#L122-L150","documentation":"ConversionSupport.convert throws ConversionException when no registered StringToObjectConverter handles the target type and the convention-based fallback (a single non-private static factory method or constructor accepting String/CharSequence) does not apply. The target type is unsupported for String conversion.","triggerScenarios":"A parameterized-test parameter of an arbitrary type that has no built-in converter, no single-String static factory, and no single-String constructor - e.g. a POJO with multiple or no String-based factories.","commonSituations":"Adding a new domain-type parameter to a @ParameterizedTest without a converter; type whose factory methods are ambiguous (more than one candidate, which the fallback ignores).","solutions":["Register a custom ArgumentConverter via @ConvertWith on the parameter.","Add a single non-private static factory method (e.g. static Person from(String)) or a single-String constructor to the target type.","Change the parameter to String and construct the target object inside the test."],"exampleFix":"// before\n@ParameterizedTest\n@CsvSource({ \"alice,30\" })\nvoid test(Person p) { }   // Person has no String factory\n\n// after\n@ParameterizedTest\n@CsvSource({ \"alice,30\" })\nvoid test(@ConvertWith(PersonConverter.class) Person p) { }\n// or give Person: public static Person from(String csv) { ... }","handlingStrategy":"validation","validationCode":"// Detect unsupported target types before the test runs.\nClass<?> target = Person.class;\nboolean hasBuiltIn = List.of(\n    Boolean.class, Character.class, Number.class, Class.class,\n    java.time.temporal.Temporal.class, java.io.File.class,\n    java.nio.file.Path.class, java.nio.charset.Charset.class,\n    java.util.UUID.class, java.net.URI.class, java.net.URL.class,\n    java.util.Currency.class, java.util.Locale.class)\n    .stream().anyMatch(c -> c.isAssignableFrom(target));\nboolean singleStringFactory =\n    java.util.Arrays.stream(target.getMethods())\n        .filter(m -> java.lang.reflect.Modifier.isStatic(m.getModifiers())\n            && !java.lang.reflect.Modifier.isPrivate(m.getModifiers())\n            && m.getParameterCount() == 1\n            && (m.getParameterTypes()[0] == String.class\n                || m.getParameterTypes()[0] == CharSequence.class)\n            && target.isAssignableFrom(m.getReturnType()))\n        .count() == 1;\nif (!hasBuiltIn && !singleStringFactory && !target.isEnum()) {\n    throw new IllegalStateException(target + \" has no String converter; register @ConvertWith\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ConversionSupport.convert(source, targetType, null);\n} catch (ConversionException e) {\n    if (e.getMessage().startsWith(\"No built-in converter\")) {\n        // add a custom ArgumentConverter or a single-String factory/constructor on the target type\n    } else throw e;\n}","preventionTips":["Register a custom ArgumentConverter via @ConvertWith for domain types.","Give target types a single non-private static from(String) factory or String constructor.","Accept String parameters and construct manually when conversion is ambiguous."],"tags":["junit","platform-commons","conversion","type-mismatch","parameterized-test"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}