datawhalechina/hello-agents · error · Exception

Theorem parameters must be uppercase letters and , only. The

Error message

Theorem parameters must be uppercase letters and , only. The current theorem contains invalid characters '{str(error_paras)}'.

What it means

Raised in _parse_theorem when the parameter segment returned by parse_fact() contains any character that fails str.isupper() (lowercase letters, digits, parentheses remnants, non-ASCII characters). The solver's theorem format only allows uppercase single-letter parameters separated by commas, because each character is treated as one parameter variable. Any other character makes substitution into the GPL premises impossible, so parsing is aborted.

Source

Thrown at Co-creation-projects/BitSecret-GPSAgent/src/gps/symbolic_solver.py:1267

        return '\n'.join(result)

    def _parse_theorem(self, theorem):
        try:
            theorem_name, theorem_paras = parse_fact(theorem.replace(' ', ''))
        except Exception as e:
            e_msg = (f"Error '{repr(e)}' occurred while parsing the theorem '{theorem}'. "
                     f"The theorem format is incorrect.")
            raise Exception(e_msg)

        if theorem_name not in self.parsed_gdl["Theorems"]:
            e_msg = f"Unknown theorem name: '{theorem_name}'."
            raise Exception(e_msg)

        error_paras = set([char for char in theorem_paras if not char.isupper()])
        if len(error_paras) > 0:
            e_msg = (f"Theorem parameters must be uppercase letters and , only. "
                     f"The current theorem contains invalid characters '{str(error_paras)}'.")
            raise Exception(e_msg)

        if len(theorem_paras) != 0 and len(theorem_paras) != len(self.parsed_gdl["Theorems"][theorem_name]['paras']):
            e_msg = (f"'{theorem}' has wrong number of parameters "
                     f"(expected {len(self.parsed_gdl["Theorems"][theorem_name]['paras'])}).")
            raise Exception(e_msg)

        if len(theorem_paras) == 0:
            theorem_paras = None

        return theorem_name, theorem_paras

    def apply(self, theorem):
        old_fact_id = len(self.facts)
        old_goal_id = len(self.goals)
        old_goal_status = self.status_of_goal.copy()
        theorem_name, theorem_paras = self._parse_theorem(theorem)

        if theorem_paras is not None:

View on GitHub (pinned to 606a07d341)

Solutions

  1. Rewrite all parameters as single uppercase letters separated by commas: 'midline(ABC)' not 'midline(a,b,c1)'.
  2. If multi-character identifiers are required, they are unsupported by this format — map them to single uppercase letters and keep the mapping outside the solver.
  3. Sanitize the theorem string before calling apply/decompose: re.sub(r'[^A-Z,]', '', paras).

Example fix

# before
solver.apply('similar_triangle(tri1, tri2)')  # digits + lowercase

# after
solver.apply('similar_triangle(A,B,C,D,E,F)')  # single uppercase letters only
Defensive patterns

Strategy: validation

Validate before calling

import re
def valid_theorem_params(theorem):
    paras = theorem.split('(', 1)[1].rsplit(')', 1)[0] if '(' in theorem else ''
    return re.fullmatch(r'[A-Z,]*', paras) is not None

Try / catch

try:
    solver.apply(theorem)
except Exception as e:
    if 'uppercase letters' in str(e):
        theorem = re.sub(r'[^A-Z,(]', '', theorem)  # sanitize and retry once

Prevention

When it happens

Trigger: Passing a theorem whose parameters contain lowercase point names ('triangle(a,b,c)'), multi-character identifiers ('triangle(AB,CD)'), digits, or leftover formatting like underscores. Note the whole parameter string is iterated character-by-character, so commas are the only accepted separator and every other char must be A-Z.

Common situations: LLM agents generating lowercase or multi-letter point labels; users accustomed to 'point P1' style naming; parameter strings that still contain brackets after parse_fact.

Understand the failure class

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/daa671f9d0cb3aa8. Report an issue: GitHub.