{"record":{"id":"939624d96b54f846","repo":"mybatis/mybatis-3","slug":"a-mapper-element-may-only-specify-a-url-resource","errorCode":null,"errorMessage":"A mapper element may only specify a url, resource or class, but not more than one.","messagePattern":"A mapper element may only specify a url, resource or class, but not more than one\\.","errorType":"validation","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java","lineNumber":418,"sourceCode":"        if (resource != null && url == null && mapperClass == null) {\n          ErrorContext.instance().resource(resource);\n          try (InputStream inputStream = Resources.getResourceAsStream(resource)) {\n            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,\n                configuration.getSqlFragments());\n            mapperParser.parse();\n          }\n        } else if (resource == null && url != null && mapperClass == null) {\n          ErrorContext.instance().resource(url);\n          try (InputStream inputStream = Resources.getUrlAsStream(url)) {\n            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url,\n                configuration.getSqlFragments());\n            mapperParser.parse();\n          }\n        } else if (resource == null && url == null && mapperClass != null) {\n          Class<?> mapperInterface = Resources.classForName(mapperClass);\n          configuration.addMapper(mapperInterface);\n        } else {\n          throw new BuilderException(\n              \"A mapper element may only specify a url, resource or class, but not more than one.\");\n        }\n      }\n    }\n  }\n\n  private boolean isSpecifiedEnvironment(String id) {\n    if (environment == null) {\n      throw new BuilderException(\"No environment specified.\");\n    }\n    if (id == null) {\n      throw new BuilderException(\"Environment requires an id attribute.\");\n    }\n    return environment.equals(id);\n  }\n\n  private static Configuration newConfig(Class<? extends Configuration> configClass) {\n    try {","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java#L400-L436","documentation":"Thrown while parsing the <mappers> section of mybatis-config.xml when a single <mapper> element does not specify exactly one of the attributes resource, url, or class. The parser branches on which combination is present; the final else branch catches both 'none specified' and 'more than one specified' with this single message. It is a configuration-format error raised at SqlSessionFactoryBuilder build time, before any session is opened.","triggerScenarios":"A <mapper/> element with (a) no attributes at all, (b) two or all three of resource/url/class set, e.g. <mapper resource=\"mappers/User.xml\" class=\"com.acme.UserMapper\"/>. Raised from XMLConfigBuilder.mapperElement() during new SqlSessionFactoryBuilder().build(reader).","commonSituations":"Copy-pasting mapper entries and forgetting to delete the old attribute; migrating from XML mappers to annotation/class mappers and leaving resource behind; typos in attribute names (e.g. 'resouce') so the real attribute is never read and all three read as null, producing the same error via the 'none specified' path.","solutions":["Set exactly one of resource, url, or class on each <mapper> element and remove the others","If no attribute is set, add the one you intended (class='com.acme.UserMapper' for interface mappers, resource='path/in/classpath/UserMapper.xml' for XML files)","Use <package name=\"com.acce.mappers\"/> instead of many <mapper class=.../> entries when registering a whole package"],"exampleFix":"<!-- before -->\n<mapper resource=\"mappers/UserMapper.xml\" class=\"com.acme.UserMapper\"/>\n\n<!-- after -->\n<mapper resource=\"mappers/UserMapper.xml\"/>","handlingStrategy":"validation","validationCode":"for (Element m : mapperElements) {\n  int specified = Stream.of(\"resource\",\"url\",\"class\")\n      .map(a -> m.getAttribute(a)).filter(a -> !a.isEmpty()).toArray().length;\n  if (specified != 1) throw new IllegalStateException(\"<mapper> at \" + location + \" must set exactly one of resource/url/class, found \" + specified);\n}","typeGuard":null,"tryCatchPattern":"catch (BuilderException e) when starting up: fail fast and report the mapper element; config errors are not recoverable at runtime — fix the XML.","preventionTips":["Validate mybatis-config.xml against mybatis-3-config.xsd in CI","Use <package> registration for bulk mapper packages"],"tags":["mybatis","xml-config","mapper-registration"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}