{"record":{"id":"54104f029e851ef2","repo":"pandas-dev/pandas","slug":"missing-values-must-be-missing-in-the-same-locatio","errorCode":null,"errorMessage":"missing values must be missing in the same location both left and right sides","messagePattern":"missing values must be missing in the same location both left and right sides","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/interval.py","lineNumber":620,"sourceCode":"        * dtype is correct\n        * left and right match lengths\n        * left and right have the same missing values\n        * left is always below right\n        \"\"\"\n        if not isinstance(dtype, IntervalDtype):\n            msg = f\"invalid dtype: {dtype}\"\n            raise ValueError(msg)\n        if len(left) != len(right):\n            msg = \"left and right must have the same length\"\n            raise ValueError(msg)\n        left_mask = notna(left)\n        right_mask = notna(right)\n        if not (left_mask == right_mask).all():\n            msg = (\n                \"missing values must be missing in the same \"\n                \"location both left and right sides\"\n            )\n            raise ValueError(msg)\n        if not (left[left_mask] <= right[left_mask]).all():\n            msg = \"left side of interval must be <= right side\"\n            raise ValueError(msg)\n\n    def _shallow_copy(self, left, right) -> Self:\n        \"\"\"\n        Return a new IntervalArray with the replacement attributes\n\n        Parameters\n        ----------\n        left : Index\n            Values to be used for the left-side of the intervals.\n        right : Index\n            Values to be used for the right-side of the intervals.\n        \"\"\"\n        dtype = IntervalDtype(left.dtype, closed=self.closed)\n        left, right, dtype = self._ensure_simple_new_inputs(left, right, dtype=dtype)\n","sourceCodeStart":602,"sourceCodeEnd":638,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/interval.py#L602-L638","documentation":"Raised by `_validate` when the NA mask of `left` differs from the NA mask of `right`. An interval is either fully present or fully missing at each position; a half-NaN interval is meaningless. Fires at pandas/core/arrays/interval.py:620.","triggerScenarios":"`from_arrays([1, np.nan, 3], [2, 4, np.nan])` — position 1 has NaN left but a real right value.","commonSituations":"Joining bound columns where one has missing timestamps and the other does not; ETL that nulls only one endpoint.","solutions":["Co-locate NA: `mask = left.isna() | right.isna(); left[mask] = right[mask] = np.nan`.","Drop rows where either side is NA before constructing: `df.dropna(subset=['lo','hi'])`.","Impute the missing bound from domain knowledge before building intervals."],"exampleFix":"// before\npd.IntervalIndex.from_arrays(df['lo'], df['hi'])  # NA misaligned\n// after\nm = df['lo'].isna() | df['hi'].isna()\ndf = df.loc[~m]\npd.IntervalIndex.from_arrays(df['lo'], df['hi'])","handlingStrategy":"validation","validationCode":"import numpy as np\nimport pandas as pd\n\ndef colocate_na(left, right):\n    left = pd.Series(left)\n    right = pd.Series(right)\n    mask = left.isna() | right.isna()\n    left[mask] = np.nan\n    right[mask] = np.nan\n    return left.to_numpy(), right.to_numpy()","typeGuard":"import pandas as pd\n\ndef na_masks_match(left, right) -> bool:\n    return (pd.notna(left) == pd.notna(right)).all()","tryCatchPattern":"try:\n    ia = pd.IntervalArray(left, right)\nexcept ValueError as e:\n    if \"missing in the same location\" in str(e):\n        l, r = colocate_na(left, right)\n        ia = pd.IntervalArray(l, r)\n    else:\n        raise","preventionTips":["Co-locate NA before constructing: set both sides NA where either is NA.","Drop rows with partial NA in ETL preprocessing.","Assert na_masks_match(left, right) in unit tests."],"tags":["interval","missing-values","validation","nan"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}