{"record":{"id":"89a5ec1b0252e26a","repo":"chroma-core/chroma","slug":"expected-embeddingfunction-call-to-have-the-fo","errorCode":null,"errorMessage":"Expected EmbeddingFunction.__call__ to have the following signature: {protocol_signature}, got {function_signature}\nPlease see https://docs.trychroma.com/guides/embeddings for details of the EmbeddingFunction interface.\nPlease note the recent change to the EmbeddingFunction interface: https://docs.trychroma.com/deployment/migration#migration-to-0.4.16---november-7,-2023 \n","messagePattern":"Expected EmbeddingFunction\\.__call__ to have the following signature: (.+?), got (.+?)\nPlease see https://docs\\.trychroma\\.com/guides/embeddings for details of the EmbeddingFunction interface\\.\nPlease note the recent change to the EmbeddingFunction interface: https://docs\\.trychroma\\.com/deployment/migration#migration-to-0\\.4\\.16---november-7,-2023 \n","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/api/types.py","lineNumber":1002,"sourceCode":"\n    def max_tokens(self) -> int:\n        return 256\n\n    @staticmethod\n    def validate_config(config: Dict[str, Any]) -> None:\n        return\n\n\ndef validate_embedding_function(\n    embedding_function: EmbeddingFunction[Embeddable],\n) -> None:\n    function_signature = signature(\n        embedding_function.__class__.__call__\n    ).parameters.keys()\n    protocol_signature = signature(EmbeddingFunction.__call__).parameters.keys()\n\n    if not function_signature == protocol_signature:\n        raise ValueError(\n            f\"Expected EmbeddingFunction.__call__ to have the following signature: {protocol_signature}, got {function_signature}\\n\"\n            \"Please see https://docs.trychroma.com/guides/embeddings for details of the EmbeddingFunction interface.\\n\"\n            \"Please note the recent change to the EmbeddingFunction interface: https://docs.trychroma.com/deployment/migration#migration-to-0.4.16---november-7,-2023 \\n\"\n        )\n\n\nclass DataLoader(Protocol[L]):\n    def __call__(self, uris: URIs) -> L:\n        ...\n\n\ndef validate_ids(ids: IDs) -> IDs:\n    \"\"\"Validates ids to ensure it is a list of strings\"\"\"\n    if not isinstance(ids, list):\n        raise ValueError(f\"Expected IDs to be a list, got {type(ids).__name__} as IDs\")\n    if len(ids) == 0:\n        raise ValueError(f\"Expected IDs to be a non-empty list, got {len(ids)} IDs\")\n    seen = set()","sourceCodeStart":984,"sourceCodeEnd":1020,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/api/types.py#L984-L1020","documentation":"Chroma pins custom embedding functions to a protocol: __call__ must have exactly the parameter names of EmbeddingFunction.__call__ (currently 'def __call__(self, input) -> Embeddings'). validate_embedding_function (chromadb/api/types.py:993) compares parameter-name sets with inspect.signature and raises on any mismatch - a parameter named 'texts' instead of 'input' fails even with correct types. The check runs when a Collection is created with an embedding_function (CollectionCommon.py:138) and when functions are resolved from configuration, so a non-conforming function fails immediately.","triggerScenarios":"A custom embedding function defined as 'def __call__(self, texts)' (wrong parameter name); extra parameters such as 'def __call__(self, input, model)'; legacy pre-0.4.16 embedding functions; callable wrappers (e.g. LangChain or sentence-transformers adapters) whose __call__ signature differs from the protocol.","commonSituations":"Upgrading chromadb across the 0.4.16 interface change; porting third-party embedding wrappers; renaming parameters for style; custom EFs written against old documentation.","solutions":["Define __call__ with the exact protocol signature: def __call__(self, input: Documents) -> Embeddings - the parameter must be named 'input'","Subclass chromadb.api.types.EmbeddingFunction so signature drift is caught by your type checker","Wrap legacy functions in a small adapter class with the conforming signature instead of editing vendor code","For config-driven embedding functions, implement name()/get_config()/build_from_config() so Chroma recognizes the function"],"exampleFix":"# before\nclass MyEF:\n    def __call__(self, texts):\n        return [embed(t) for t in texts]\n\n# after\nclass MyEF(EmbeddingFunction):\n    def __call__(self, input):\n        return [embed(t) for t in input]","handlingStrategy":"type-guard","validationCode":"from inspect import signature\n\ndef conforms_to_ef_protocol(fn) -> bool:\n    got = list(signature(fn.__class__.__call__).parameters)\n    want = list(signature(EmbeddingFunction.__call__).parameters)\n    return got == want\n\nassert conforms_to_ef_protocol(my_ef), 'EF signature does not match protocol'","typeGuard":"from inspect import signature\nfrom chromadb.api.types import EmbeddingFunction\n\ndef is_conforming_embedding_function(fn) -> bool:\n    try:\n        return list(signature(fn.__class__.__call__).parameters) == list(signature(EmbeddingFunction.__call__).parameters)\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    col = client.create_collection(name='c', embedding_function=my_ef)\nexcept ValueError as e:\n    if 'EmbeddingFunction.__call__' in str(e):\n        raise RuntimeError('custom EF must define __call__(self, input)') from e\n    raise","preventionTips":["Subclass chromadb.api.types.EmbeddingFunction so type checkers catch drift","Name the parameter 'input' - names are compared, not just arity","Add a startup smoke test that creates a collection with each custom EF","Wrap third-party embedders in an adapter with the protocol signature"],"tags":["chromadb","python","embedding-function","interface","migration"],"backgroundTag":"embedding-function-signature-mismatch","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}