{"record":{"id":"d8f1e98aa362995c","repo":"langchain-ai/langchain","slug":"alternative-import-must-be-a-fully-qualified-modul","errorCode":null,"errorMessage":"alternative_import must be a fully qualified module path. Got  {alternative_import}","messagePattern":"alternative_import must be a fully qualified module path\\. Got  (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/_api/deprecation.py","lineNumber":117,"sourceCode":"    alternative: str,\n    alternative_import: str,\n    *,\n    pending: bool,\n) -> None:\n    \"\"\"Validate the deprecation parameters.\"\"\"\n    if pending and removal:\n        msg = \"A pending deprecation cannot have a scheduled removal\"\n        raise ValueError(msg)\n    if alternative and alternative_import:\n        msg = \"Cannot specify both alternative and alternative_import\"\n        raise ValueError(msg)\n\n    if alternative_import and \".\" not in alternative_import:\n        msg = (\n            \"alternative_import must be a fully qualified module path. Got \"\n            f\" {alternative_import}\"\n        )\n        raise ValueError(msg)\n\n\ndef deprecated(\n    since: str,\n    *,\n    message: str = \"\",\n    name: str = \"\",\n    alternative: str = \"\",\n    alternative_import: str = \"\",\n    pending: bool = False,\n    obj_type: str = \"\",\n    addendum: str = \"\",\n    removal: str = \"\",\n    package: str = \"\",\n) -> Callable[[T], T]:\n    \"\"\"Decorator to mark a function, a class, or a property as deprecated.\n\n    When deprecating a classmethod, a staticmethod, or a property, the `@deprecated`","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/_api/deprecation.py#L99-L135","documentation":"Raised by `_validate_deprecation_params` when `alternative_import` is supplied but contains no dot, i.e. it is not a fully qualified module path. The decorator uses the dotted path both to render 'import x.y.z' guidance in the warning and to surface the replacement object to tooling, so a bare name is rejected.","triggerScenarios":"`@deprecated(since=\"0.3\", alternative_import=\"new_fn\")` — a single identifier with no `.`. Note the rendered message contains a stray double space ('Got  {alternative_import}') due to the f-string in the source; the underlying check is simply `'.' not in alternative_import`.","commonSituations":"Copy-pasting just the symbol name instead of its full path, or refactoring a module and updating the alternative to a name that lost its package prefix.","solutions":["Use the fully qualified import path of the replacement: `alternative_import=\"langchain_x.new_module.new_fn\"`.","If no module path exists for the replacement, switch to the free-text `alternative=` kwarg instead (they are mutually exclusive anyway)."],"exampleFix":"# before\n@deprecated(\"0.3\", alternative_import=\"new_fn\")\n\n# after\n@deprecated(\"0.3\", alternative_import=\"mymod.submod.new_fn\")","handlingStrategy":"validation","validationCode":"import re\n\ndef is_qualified_path(path: str) -> bool:\n    return bool(re.fullmatch(r\"[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)+\", path))\n\nassert is_qualified_path(\"mymod.new_fn\") and not is_qualified_path(\"new_fn\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy alternative_import from an actual working import statement, then delete the 'from ... import ' wrapper text.","CI smoke-import of deprecated modules catches malformed paths immediately."],"tags":["deprecation","langchain-core","api-misuse"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}