{"record":{"id":"c4bcf33320e71df4","repo":"jumpserver/jumpserver","slug":"failed-to-capture-shell-state-before-switching-use-c4bcf3","errorCode":null,"errorMessage":"Failed to capture shell state before switching user. The login shell did not return a verification marker.","messagePattern":"Failed to capture shell state before switching user\\. The login shell did not return a verification marker\\.","errorType":"error_code","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"apps/libs/ansible/modules_utils/remote_client.py","lineNumber":658,"sourceCode":"        baseline_output, baseline_error = self.execute(\n            [switch_state_cmd],\n            [switch_state_re]\n        )\n        baseline_state = _extract_switch_state(baseline_output)\n        self._debug(\n            'privilege.user.baseline',\n            output=baseline_output,\n            error=baseline_error,\n            state=baseline_state,\n        )\n        if baseline_error:\n            raise RuntimeError(\n                'Failed to capture shell state before switching user. '\n                f'Output: {self._redact_text(baseline_output)}. '\n                f'Error: {self._redact_text(baseline_error)}'\n            )\n        if baseline_state is None:\n            raise RuntimeError(\n                'Failed to capture shell state before switching user. '\n                'The login shell did not return a verification marker.'\n            )\n\n        # A root `su` or NOPASSWD sudo may open the target shell without\n        # displaying a password prompt. Read until either the deterministic\n        # prompt appears or the channel becomes quiet, then only send the\n        # secret when a prompt was actually observed.\n        output_parts = []\n        error = ''\n        authentication_error = None\n        password_sent = False\n        try:\n            channel = self.channel\n            self._check_send(channel)\n            self._send_command(channel, switch_cmd)\n            switch_output = self._get_match_recv(\n                prompt_re,","sourceCodeStart":640,"sourceCodeEnd":676,"githubUrl":"https://github.com/jumpserver/jumpserver/blob/6ec464fabd61b95912d539455a3a5f15f5c59fe0/apps/libs/ansible/modules_utils/remote_client.py#L640-L676","documentation":"Raised when the baseline marker command completed without error but produced no parseable verification marker (baseline_state is None). Without a baseline state the client cannot later prove the user switch took effect.","triggerScenarios":"The login shell returns output that doesn't match the marker pattern — paging headers, banners, or CLI output swallowing the marker — or returns empty output.","commonSituations":"Network devices printing MOTB/banners around command output; terminal paging (--more--) interleaving; delay/timeout too short so marker arrives after the read window; custom prompts confusing the parser.","solutions":["Increase recv_timeout and set an adequate delay_time so the marker is fully captured.","Disable paging/banners on the device for this session.","Check debug logs ('privilege.user.baseline') to see the raw output and why the pattern missed."],"exampleFix":"# before\n- name: run module\n  my_module:\n    recv_timeout: 15\n# after\n- name: run module\n  my_module:\n    recv_timeout: 60\n    delay_time: 10","handlingStrategy":"validation","validationCode":"# Ensure enough time for the marker round-trip\n- set_fact:\n    recv_timeout: \"{{ recv_timeout | default(60) }}\"\n- assert: { that: \"recv_timeout | int > delay_time | int(0)\" }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Raise recv_timeout on banner-heavy devices.","Disable MOTD/paging where possible.","Inspect 'privilege.user.baseline' debug output on failure."],"tags":["ansible","become","marker","parsing","timeout"],"backgroundTag":"unexpected-output-format","analyzedSha":"6ec464fabd61b95912d539455a3a5f15f5c59fe0","analyzedAt":"2026-08-28T11:33:00.925Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}