{"record":{"id":"4224b6ddd1287951","repo":"xai-org/x-algorithm","slug":"non-optional-parameter-s-must-be-declared-before","errorCode":null,"errorMessage":"Non-optional parameter %s must be declared before optional parameters.","messagePattern":"Non-optional parameter (.+?) must be declared before optional parameters\\.","errorType":"validation","errorClass":"ParseFailure","httpStatus":null,"severity":"error","filePath":"botmaker/src/java/com/twitter/botmaker/compiler/Parser.java","lineNumber":176,"sourceCode":"            \"Failed to parse DF signature '%s'%s\", s, extraMsg), re);\n      }\n      throw new ParseFailure(\"unknown parse failure\", e);\n    }\n\n    return buildParams(root);\n  }\n\n  private static ImmutableList<Tuple3<Tree, String, Optional<Tree>>> buildParams(\n      Tree params) throws ParseFailure {\n    ImmutableList.Builder<Tuple3<Tree, String, Optional<Tree>>> ret = ImmutableList.builder();\n    Set<String> argNames = Sets.newHashSet();\n    boolean hasOpt = false;\n    for (int i = 0; i < params.getChildCount(); i++) {\n      Tree arg = params.getChild(i);\n      if (arg.getType() == BotMakerLexer.ARG) {\n        String name = arg.getChild(1).getText();\n        if (arg.getChildCount() == 2 && hasOpt) {\n          throw new ParseFailure(\n              String.format(\n                  \"Non-optional parameter %s must be declared before optional parameters.\",\n                  name));\n        } else if (arg.getChildCount() == 2) {\n          ret.add(Tuple.of(arg.getChild(0), name, Optional.absent()));\n        } else {\n          hasOpt = true;\n          ret.add(Tuple.of(arg.getChild(0), name, Optional.of(arg.getChild(2))));\n        }\n\n        if (argNames.contains(name)) {\n          throw new ParseFailure(\"Duplicated argument name \" + name);\n        }\n        argNames.add(name);\n      }\n    }\n    return ret.build();\n  }","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/botmaker/src/java/com/twitter/botmaker/compiler/Parser.java#L158-L194","documentation":"Enforced by Parser.buildParams: once a parameter with a default value (optional parameter) appears, no later parameter may omit a default. This mirrors the Java/Scala rule that optional/defaulted parameters must trail required ones, keeping positional argument construction unambiguous.","triggerScenarios":"A params/DF signature like #param(a, b=1, c) where c has no default but follows optional b. Detected while iterating ARG nodes: an ARG with only 2 children (no default) appearing after hasOpt was set.","commonSituations":"Editing parameter lists and appending a new required param at the end, or reordering parameters during refactors of a DF signature without re-checking defaults.","solutions":["Give the trailing non-optional parameter a default value, or move it before the first optional parameter","If the parameter must be required, make all preceding optional parameters required too","Add a lint/unit test over signature definitions to catch ordering violations at build time"],"exampleFix":"// before\n#params(x, opt=1, required)\n\n// after\n#params(required, x, opt=1)","handlingStrategy":"validation","validationCode":"// Validate before parsing: required params must precede optional ones\nboolean validOrder(List<Param> ps) {\n  boolean seenOpt = false;\n  for (Param p : ps) {\n    if (p.defaultValue.isPresent()) seenOpt = true;\n    else if (seenOpt) return false;\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try { Parser.parseParams(sig); } catch (ParseFailure pf) { /* message names the offending param */ }","preventionTips":["Treat 'append required param at end' edits as a red flag","Add a build-time lint over all DF signatures","Encode the rule in code review checklists"],"tags":["parsing","parameter-ordering","validation","botmaker"],"backgroundTag":"required-parameter-after-optional","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}