#1996·outlines

JsonSchema and CFG are unhashable: defining __eq__ without __hash__ sets __hash__ = None

Author: harsh4vardhanCreated Aug 13, 2026Updated Aug 13, 2026

Bug Description

JsonSchema and CFG both define __eq__ without defining __hash__. Per the Python data model, when a class defines __eq__ but not __hash__, Python silently sets __hash__ = None, making instances unhashable. This means neither type can be used in a set or as a dict key.

Affected files

  • src/outlines/types/dsl.pyJsonSchema.__eq__ at line 447 (no __hash__ defined)
  • src/outlines/types/dsl.pyCFG is a @dataclass that defines explicit __eq__ at line 258, which suppresses the dataclass-generated __hash__

Minimal reproducer

python
from outlines.types.dsl import JsonSchema, CFG

js = JsonSchema('{"type": "string"}')
print(JsonSchema.__hash__)  # None
hash(js)                    # TypeError: unhashable type: 'JsonSchema'
{js}                        # TypeError: unhashable type: 'JsonSchema'

cfg = CFG("root ::= [0-9]+")
print(CFG.__hash__)         # None
hash(cfg)                   # TypeError: unhashable type: 'CFG'
{cfg: "value"}              # TypeError: unhashable type: 'CFG'

Why this matters

Any code that stores output types in a set or uses them as dict keys will fail at runtime with a TypeError. This includes cache key construction, deduplication of output types, and any future caching layer over JsonSchema or CFG instances.

Suggested fix

Add __hash__ implementations consistent with the __eq__ semantics already defined.

JsonSchema — hash on normalised JSON (sorted keys) so equivalent schemas hash equally:

python
def __hash__(self):
    try:
        normalised = json.dumps(json.loads(self.schema), sort_keys=True)
    except json.JSONDecodeError:
        normalised = self.schema
    return hash((normalised, self.whitespace_pattern))

CFG — add unsafe_hash=True to the @dataclass decorator, or add:

python
def __hash__(self):
    return hash(self.definition)

Environment

Reproduced on Python 3.12 with Outlines main branch (2026-08-13).