{"record":{"id":"e60940302df9c690","repo":"arduino/Arduino","slug":"throw-new-preferencesmapexception-key","errorCode":null,"errorMessage":"throw new PreferencesMapException(key)","messagePattern":"throw new PreferencesMapException\\(key\\)","errorType":"exception","errorClass":"PreferencesMapException","httpStatus":null,"severity":"error","filePath":"arduino-core/src/processing/app/helpers/StringReplacer.java","lineNumber":67,"sourceCode":"      break;\n    }\n\n    // Inject tag inside the dictionary\n    dict.put(key, tag);\n\n    // Recursive replace with a max depth of 10 levels.\n    String res;\n    for (int i = 0; i < 10; i++) {\n      // Do a replace with dictionary\n      res = StringReplacer.replaceFromMapping(src, dict);\n      if (res.equals(src))\n        break;\n      src = res;\n    }\n\n    // If the resulting string contains the tag, then the key is required\n    if (src.contains(tag)) {\n      throw new PreferencesMapException(key);\n    }\n  }\n\n  public static String[] formatAndSplit(String src, Map<String, String> dict) throws Exception {\n    String res;\n\n    // Recursive replace with a max depth of 10 levels.\n    for (int i = 0; i < 10; i++) {\n      // Do a replace with dictionary\n      res = StringReplacer.replaceFromMapping(src, dict);\n      if (res.equals(src))\n        break;\n      src = res;\n    }\n\n    // Split the resulting string in arguments\n    return quotedSplit(src, \"\\\"'\", false);\n  }","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/arduino/Arduino/blob/a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee/arduino-core/src/processing/app/helpers/StringReplacer.java#L49-L85","documentation":"StringReplacer.checkIfRequiredKeyIsMissingOrExcept verifies that after substituting all known {key} placeholders from the dictionary, no unresolved tag remains in the string. If a placeholder cannot be resolved, it throws PreferencesMapException(key) signalling that a required build property is missing from preferences. This enforces that recipes like compiler recipes have all their required variables defined.","triggerScenarios":"Formatting a build recipe/pattern (via StringReplacer/PReferencesMap-based substitution) where a {placeholder} in the recipe string has no corresponding key in the supplied preferences map — e.g. recipe.c.o.pattern referencing {compiler.c.extra_flags} that is undefined.","commonSituations":"Custom or third-party platform.txt recipes referencing variables never defined; typo'd key in a recipe; removed/renamed preference in a newer IDE used by an old platform definition; user-overridden build.path/runtime vars deleted in platform.local.txt.","solutions":["Define the reported key in platform.txt/boards.txt or pass it via compiler/recipe extra flags","Fix the typo in the recipe placeholder so it matches a defined preference","Upgrade the platform to a version compatible with the IDE's expected variables","Temporarily echo the recipe with all variables to see which value is empty (verbose compile)"],"exampleFix":"// before\nrecipe.c.o.pattern=\"{compiler.gcc.path}{compiler.gcc.cmd} ... {compiler.some.undefined.flag}\" // throws\n// after: define it or make it optional\nrecipe.c.o.pattern=\"{compiler.gcc.path}{compiler.gcc.cmd} ... {compiler.c.extra_flags}\"\ncompiler.c.extra_flags=\"\"","handlingStrategy":"validation","validationCode":"Set<String> keys = collectPlaceholders(recipePattern); // regex \\{([^}]+)\\}\nfor (String k : keys)\n  if (prefs.get(k) == null)\n    throw new IllegalStateException(\"Recipe references undefined key: \" + k);","typeGuard":null,"tryCatchPattern":"try {\n  StringReplacer.checkIfRequiredKeyIsMissingOrExcept(pattern, dict, tag);\n} catch (PreferencesMapException e) {\n  logger.error(\"Recipe variable undefined: \" + e.getMessage());\n}","preventionTips":["Verify every {placeholder} in custom recipes exists in preferences","Compile with verbose output to spot empty substitutions early","Keep platform.txt recipes in sync with IDE variable names","Use extra_flags for optional values instead of hard references"],"tags":["string-replacement","missing-key","arduino-build","recipe"],"backgroundTag":"missing-config-key","analyzedSha":"a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee","analyzedAt":"2026-09-06T10:13:38.901Z","contentChangedAt":"2026-09-06T10:13:38.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}