UnknownFormatConversionException 是因 String.format() 解析非法格式符(如 %z、%@)抛出的运行时异常,常见于日志模板误用 Java 原生语法、配置文件中百分号未转义(应写为 %%)、动态模板含未校验非法字符等场景。

UnknownFormatConversionException 通常不是日志框架本身抛出的,而是底层使用的 String.format()(或类似格式化逻辑)在解析模板字符串时,遇到无法识别的格式化符号(如 %z、%@、%& 等非法转换符)而触发的运行时异常。
日志模板中混入了非法的 % 占位符
很多日志框架(如 Log4j、SLF4J + Logback)支持类似 String.format() 的占位语法(如 {} 或 %s),但具体支持哪些取决于实际绑定的实现。若你误用了 Java 原生 String.format() 的语法(比如写成 "User %z logged in"),而 %z 并非标准格式转换符,JVM 就会在执行格式化时直接抛出 UnknownFormatConversionException。
- 常见非法写法:
"Time: %tZ"(缺少参数类型)、"Value: %q"(q不是合法转换符)、"ID: %05d"(在不支持宽度修饰的上下文中使用) - 注意:SLF4J 的
{}占位符 不经过String.format(),所以不会触发该异常;但如果你手动调用String.format(template, args)构造日志消息,就可能中招
日志配置文件里模板字符串被意外转义或拼接
在 logback.xml 或 log4j2.xml 中定义 pattern layout 时,如果模板含裸露的 % 符号(如想输出字面量 % 却没双写),解析器可能误判为格式指令开头。
- 正确写法(输出一个百分号):
%% - 错误写法:
%(孤立单个百分号)、%+d(+不是合法修饰符)、%X{key}(但X实际未注册为 MDC 转换器) - 某些插件或自定义 PatternConverter 若未正确定义,也会让解析器把
%x当作未知转换符处理
动态拼接日志模板时未校验输入
当从外部(如配置中心、数据库、用户输入)读取日志模板字符串并用于格式化时,若未过滤或转义非法字符,极易引入不可控的占位符。
- 建议对动态模板做预检:用正则
%[^a-zA-Z%]|%$扫描潜在非法片段 - 更安全的做法是避免直接使用
String.format(),改用 SLF4J 的logger.info("Msg: {}, code: {}", msg, code)—— 它延迟格式化且不依赖%语法 - 若必须用
String.format(),先用try-catch UnknownFormatConversionException包裹,并记录原始模板便于排查
排查与修复关键点
异常堆栈通常会明确指出哪个格式符不合法(例如:java.util.UnknownFormatConversionException: Conversion = 'z'),结合日志语句和对应模板就能快速定位。
- 检查抛异常的日志语句及其传入的模板字符串(而非最终输出内容)
- 确认你用的是哪套日志 API:SLF4J 接口层?Logback 原生?还是手动调用
String.format? - 统一占位风格:团队内约定只用
{}(SLF4J 风格)或只用%s/%d(Java 格式),避免混用 - 单元测试中加入含特殊符号的模板用例,提前暴露问题

















