{"record":{"id":"45c3db06c04dd654","repo":"langchain-ai/langchain","slug":"a-pending-deprecation-cannot-have-a-scheduled-remo","errorCode":null,"errorMessage":"A pending deprecation cannot have a scheduled removal","messagePattern":"A pending deprecation cannot have a scheduled removal","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/_api/deprecation.py","lineNumber":107,"sourceCode":"\n\n# Bound is `Any` (not `FieldInfoV1`) because importing `pydantic.v1` at module\n# scope emits a `UserWarning` on Python 3.14+; v1 `FieldInfo` support is handled\n# at runtime via `_is_pydantic_v1_field_info`.\nT = TypeVar(\"T\", bound=type | Callable[..., Any] | Any)\n\n\ndef _validate_deprecation_params(\n    removal: str,\n    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 = \"\",","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/_api/deprecation.py#L89-L125","documentation":"Raised by `_validate_deprecation_params` in langchain-core's deprecation API when a decorator is declared `pending=True` while also passing a `removal` version. A pending deprecation is by definition not yet scheduled for removal, so specifying both is contradictory and the library rejects it at decoration time (import time for module/class/function decorators).","triggerScenarios":"Calling `@deprecated(since=\"0.3\", pending=True, removal=\"1.0\")` (or `warn_deprecated(..., pending=True, removal=\"1.0\")`) on a class, function, method, or Pydantic field. The check fires before any decorated object is used, so the ValueError surfaces as soon as the module is imported.","commonSituations":"A developer copies an existing `@deprecated(...)` line that had `removal=` set, then adds `pending=True` to soften the warning. Also happens when promoting a hard deprecation to pending during a release-candidate refactor and forgetting to delete the `removal` kwarg.","solutions":["Remove the `removal=` argument: `@deprecated(since=\"0.3\", pending=True)` is the valid pending form.","If you actually want a scheduled removal, drop `pending=True` instead: `@deprecated(since=\"0.3\", removal=\"1.0\")`."],"exampleFix":"# before\n@deprecated(\"0.3\", pending=True, removal=\"1.0\", alternative=\"new_fn\")\ndef old_fn(): ...\n\n# after\n@deprecated(\"0.3\", pending=True, alternative=\"new_fn\")\ndef old_fn(): ...","handlingStrategy":"validation","validationCode":"def validate_deprecation_kwargs(pending: bool, removal: str) -> None:\n    if pending and removal:\n        raise ConfigError(\"pending=True cannot be combined with removal=\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a single lint rule (ruff custom check or grep in CI) over deprecation decorators asserting not (pending and removal).","Use keyword args consistently in @deprecated calls so an extra removal= kwarg is visible in review."],"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"}