{"record":{"id":"2985e69dbf09861a","repo":"MyCATApache/Mycat-Server","slug":"unterminated-property-text","errorCode":null,"errorMessage":"Unterminated property: ${text}","messagePattern":"Unterminated property: (.+?)","errorType":"exception","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/config/util/ConfigUtil.java","lineNumber":75,"sourceCode":"    }\n\n    public static String filter(String text, Properties properties) {\n        StringBuilder s = new StringBuilder();\n        int cur = 0;\n        int textLen = text.length();\n        int propStart = -1;\n        int propStop = -1;\n        String propName = null;\n        String propValue = null;\n        for (; cur < textLen; cur = propStop + 1) {\n            propStart = text.indexOf(\"${\", cur);\n            if (propStart < 0) {\n                break;\n            }\n            s.append(text.substring(cur, propStart));\n            propStop = text.indexOf(\"}\", propStart);\n            if (propStop < 0) {\n                throw new ConfigException(\"Unterminated property: \" + text.substring(propStart));\n            }\n            propName = text.substring(propStart + 2, propStop);\n            propValue = properties.getProperty(propName);\n            if (propValue == null) {\n                s.append(\"${\").append(propName).append('}');\n            } else {\n                s.append(propValue);\n            }\n        }\n        return s.append(text.substring(cur)).toString();\n    }\n\n    public static Document getDocument(final InputStream dtd, InputStream xml) throws ParserConfigurationException,\n            SAXException, IOException {\n        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n        factory.setValidating(true);\n        factory.setNamespaceAware(false);\n        DocumentBuilder builder = factory.newDocumentBuilder();","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/config/util/ConfigUtil.java#L57-L93","documentation":"ConfigUtil.filter performs ${property} placeholder substitution in config text. When it finds '${' but never a closing '}', it throws ConfigException indicating the property reference is unterminated. This protects against silently treating malformed placeholders as literal text.","triggerScenarios":"A config value contains '${' without a matching '}', e.g. \"password=${db_pass\" or a lone '${' from an accidental paste or shell-variable expansion that was stripped.","commonSituations":"Hand-edited mycat config files (server.xml/schema.xml) with a typo in a ${...} expression; environment interpolation removing the closing brace; copy-paste truncation.","solutions":["Locate the '${' occurrence in the offending config value and add the missing closing '}'","If the literal text '${' is intended, escape or reword it so the filter does not see a placeholder","Validate all config values contain balanced '${...}' pairs before loading"],"exampleFix":"// before (in config value)\nurl=jdbc:mysql://${host:3306/db\n// after\nurl=jdbc:mysql://${host}:3306/db","handlingStrategy":"validation","validationCode":"long open = text.chars().filter(c -> c == '$').count();\nlong close = text.chars().filter(c -> c == '}').count();\nif (open != close) throw new ConfigException(\"unbalanced ${} in: \" + text);","typeGuard":null,"tryCatchPattern":"try { filtered = ConfigUtil.filter(text, props); } catch (ConfigException e) { log.error(\"bad placeholder in config: {}\", e.getMessage()); throw e; }","preventionTips":["Lint config files for balanced ${...} before deployment","Avoid pasting shell snippets containing ${ into XML configs","Keep placeholder names simple and on one line"],"tags":["config","placeholder","parsing"],"backgroundTag":"invalid-config-value","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}