Python V1 · Deprecated

Errors

Errors in the Python V1 binding.

The Python V1 errors reference continues the Python V1 overview.

Shape errors — Python TypeError / ValueError

Before any native call, the wrapper checks the shape of the arguments on the Python side and raises an ordinary built-in Python exception when it is wrong:

Input error (rejected in Python)Raises
Non-string predicateTypeError
Non-integer arity, including boolTypeError
Negative arity, or arity > engine.limits.max_arityValueError
terms is not a sequence, or is itself a str/bytes valueTypeError

max_arity here is the build profile's global ceiling, not each predicate's declared arity — the Python check only rejects an impossible arity early. A shape error almost always means a bug in the calling code, so you normally fix the call rather than catch these at runtime.

Engine errors — MaelysDatalogError

Once the call is well-shaped, the engine itself can still reject it. That surfaces as a MaelysDatalogError, a subclass of RuntimeError, carrying .code (an int), .message and .hint (see Diagnostics). Domain registration also has specialized subclasses: DomainAlreadyRegisteredError and DomainRegistryFullError. Two conditions both raise .code == ERR_INVALID_FIELD:

  • an explicit Term.symbol_id(id) that is not in this ruleset's symbol table — the id is not a valid field value;
  • an arity within the build limit that does not match the predicate's declared arity — predicate lookup matches on (name, arity) together, so a wrong arity is not a registered predicate.

It can also raise ERR_FORBIDDEN (the predicate is a POLICY_FACT kind) or ERR_PAYLOAD_TOO_LARGE (fact caps). To act on a specific code, compare .code:

CODE
from maelys_datalog import C, MaelysDatalogError

try:
    edb.add_fact('owns', [Term.symbol_id(bad_id), Term.symbol_id(doc)])
except MaelysDatalogError as exc:
    if exc.code == C.ERR_INVALID_FIELD:
        ...   # unknown symbol id, or a wrong (predicate, arity) pair

exc.code holds a maelys_result_t return code — the MAELYS_ERR_* values in the Error codes table (MAELYS_ERR_INVALID_FIELD is -2). Compare it against the matching constant from C, a namespace of engine constants the package exports (from maelys_datalog import C). Note the asymmetry: the predicate-kind flags have plain top-level names — you import PRED_EDB directly — but the error codes live only on C, under names with the MAELYS_ prefix dropped, so it is C.ERR_INVALID_FIELD (there is no top-level ERR_INVALID_FIELD to import).

Catching both

The two kinds come from different layers and share no common base below Exception: MaelysDatalogError is a RuntimeError, while TypeError and ValueError are not. So a single except MaelysDatalogError clause does not catch a shape error. To guard both at once, give each its own clause:

CODE
try:
    edb.add_fact(predicate, terms)
except (TypeError, ValueError) as exc:
    # caller passed the wrong shape (bad predicate/arity/terms type) —
    # normally a bug in your code to fix, not a runtime condition
    raise
except MaelysDatalogError as exc:
    # the engine rejected a well-shaped call — inspect the code
    if exc.code == C.ERR_INVALID_FIELD:
        ...   # unknown symbol id, or a wrong (predicate, arity) pair

In practice the first clause is a guard rail (shape bugs surface loudly during development), and the second is where the real runtime conditions land.