Troubleshooting
ImportError: cannot import name ‘X’ from ‘lexigram.contracts’
Section titled “ImportError: cannot import name ‘X’ from ‘lexigram.contracts’”Error:
ImportError: cannot import name 'MyType' from 'lexigram.contracts'Cause: The name doesn’t exist in lexigram.contracts.__init__ or the lazy imports dict, or it’s been moved to a different module.
Solution:
- Check
lexigram/contracts/__init__.pyfor the correct import path - Search the contracts source tree for the definition
- If it’s a type from an extension package, import from that package instead
# ✅ Check the contracts __init__.py for lazy importsfrom lexigram.contracts.core import ContainerRegistrarProtocolfrom lexigram.contracts.infra.cache import CacheBackendProtocolCircular Import Error
Section titled “Circular Import Error”Error:
ImportError: cannot import name 'X' from partially initialized module 'lexigram.contracts'Cause: A type in contracts is trying to import from an extension package, violating the zero-dependency rule.
Solution: Ensure lexigram-contracts only imports from stdlib and its own submodules — never from lexigram or any extension:
# ✅ Correct — stdlib onlyfrom typing import Protocolfrom dataclasses import dataclass
# ❌ Wrong — pulls in lexigramfrom lexigram.result import ResultThe Result type in contracts is defined in lexigram.contracts.core.result — independent of the lexigram package’s re-export.
Protocol Not Recognized by isinstance()
Section titled “Protocol Not Recognized by isinstance()”isinstance(my_cache, CacheBackendProtocol) # Returns False unexpectedlyCause: The protocol class is missing the @runtime_checkable decorator, or the implementation doesn’t structurally match the protocol signature.
Solution:
- Ensure the protocol has
@runtime_checkable:from typing import Protocol, runtime_checkable@runtime_checkableclass CacheBackendProtocol(Protocol):... - Verify your implementation has all the required methods with matching signatures
- Use
ProtocolValidator(inlexigram) at registration time to catch mismatches
Type Defined in Two Places
Section titled “Type Defined in Two Places”Symptom: Two different import paths for what should be the same type, leading to isinstance() failures and type errors.
Cause: A type was defined both in lexigram-contracts and in an extension package (violating the no-duplication rule).
Solution: Remove the extension package’s copy and import from contracts:
# ❌ Wrong — duplicate definition in extension packageclass CacheBackendProtocol(Protocol): ...
# ✅ Correct — import from contractsfrom lexigram.contracts.infra.cache import CacheBackendProtocolWrong Domain Directory
Section titled “Wrong Domain Directory”Symptom: Protocol or type is hard to find, or import paths don’t match the domain organization.
Cause: A type was placed in a directory named after the extension package (e.g. ai-llm/) instead of the domain (e.g. ai/llm.py).
Solution: Organize by domain, not by consumer:
# ✅ Correct — by domainlexigram/contracts/ai/llm.py
# ❌ Wrong — by packagelexigram/contracts/ai-llm/Extension Exception Doesn’t Extend Contracts Base
Section titled “Extension Exception Doesn’t Extend Contracts Base”Error:
# In extension packageclass LLMRateLimitError(Exception): # ❌ Should extend AIError or LLMError ...Cause: Leaf exceptions in extension packages must extend the corresponding base exception from contracts.
Solution:
# ✅ Correctfrom lexigram.contracts.ai.exceptions import LLMError
class LLMRateLimitError(LLMError): """Raised when rate-limited by the LLM provider."""This ensures callers can catch AIError and get all AI subsystem errors without importing extension packages.
Debug Tips
Section titled “Debug Tips”-
List all available exports:
import lexigram.contractsprint(dir(lexigram.contracts)) -
Find where a protocol is defined:
from lexigram.contracts.core.di import ContainerRegistrarProtocolprint(ContainerRegistrarProtocol.__module__) -
Verify no cross-imports:
Terminal window grep -rn "from lexigram\." lexigram-contracts/src/ --include="*.py" | grep -v "contracts" | grep -v "^Binary"Should return no results (contracts only imports from itself).
-
Check for duplicate definitions:
Terminal window grep -rn "class CacheBackendProtocol" framework/ --include="*.py"Should only appear in
lexigram-contracts.