xai-org/x-algorithm · error · ParseFailure

Non-optional parameter %s must be declared before optional p

Error message

Non-optional parameter %s must be declared before optional parameters.

What it means

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.

Source

Thrown at botmaker/src/java/com/twitter/botmaker/compiler/Parser.java:176

            "Failed to parse DF signature '%s'%s", s, extraMsg), re);
      }
      throw new ParseFailure("unknown parse failure", e);
    }

    return buildParams(root);
  }

  private static ImmutableList<Tuple3<Tree, String, Optional<Tree>>> buildParams(
      Tree params) throws ParseFailure {
    ImmutableList.Builder<Tuple3<Tree, String, Optional<Tree>>> ret = ImmutableList.builder();
    Set<String> argNames = Sets.newHashSet();
    boolean hasOpt = false;
    for (int i = 0; i < params.getChildCount(); i++) {
      Tree arg = params.getChild(i);
      if (arg.getType() == BotMakerLexer.ARG) {
        String name = arg.getChild(1).getText();
        if (arg.getChildCount() == 2 && hasOpt) {
          throw new ParseFailure(
              String.format(
                  "Non-optional parameter %s must be declared before optional parameters.",
                  name));
        } else if (arg.getChildCount() == 2) {
          ret.add(Tuple.of(arg.getChild(0), name, Optional.absent()));
        } else {
          hasOpt = true;
          ret.add(Tuple.of(arg.getChild(0), name, Optional.of(arg.getChild(2))));
        }

        if (argNames.contains(name)) {
          throw new ParseFailure("Duplicated argument name " + name);
        }
        argNames.add(name);
      }
    }
    return ret.build();
  }

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Give the trailing non-optional parameter a default value, or move it before the first optional parameter
  2. If the parameter must be required, make all preceding optional parameters required too
  3. Add a lint/unit test over signature definitions to catch ordering violations at build time

Example fix

// before
#params(x, opt=1, required)

// after
#params(required, x, opt=1)
Defensive patterns

Strategy: validation

Validate before calling

// Validate before parsing: required params must precede optional ones
boolean validOrder(List<Param> ps) {
  boolean seenOpt = false;
  for (Param p : ps) {
    if (p.defaultValue.isPresent()) seenOpt = true;
    else if (seenOpt) return false;
  }
  return true;
}

Try / catch

try { Parser.parseParams(sig); } catch (ParseFailure pf) { /* message names the offending param */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/4224b6ddd1287951. Report an issue: GitHub.