@@ -888,6 +888,42 @@ def test_stale_session_no_conv_path_no_retry(self, tmp_path):
888888 assert result .output == ""
889889 assert mock_run .call_count == 1
890890
891+ def test_auth_error_raises_runtime_error (self , tmp_path ):
892+ """is_error=True with auth failure raises RuntimeError instead of returning error text."""
893+ (tmp_path / "CLAUDE.md" ).write_text ("identity" )
894+ auth_error_text = (
895+ 'Failed to authenticate. API Error: 401 {"type":"error","error":{'
896+ '"type":"authentication_error","message":"Invalid authentication credentials"}}'
897+ )
898+ mock_result = MagicMock ()
899+ mock_result .stdout = json .dumps ({"is_error" : True , "result" : auth_error_text })
900+ mock_result .stderr = ""
901+ mock_result .returncode = 0
902+ backend = CliBackend ()
903+
904+ with patch ("clayde.claude.APP_DIR" , tmp_path ), \
905+ patch ("clayde.claude.get_settings" , return_value = _mock_settings (backend = "cli" )), \
906+ patch ("clayde.claude._resolve_cli_bin" , return_value = "/usr/bin/claude" ), \
907+ patch ("clayde.claude.subprocess.run" , return_value = mock_result ):
908+ with pytest .raises (RuntimeError , match = "authentication failed" ):
909+ backend .invoke ("prompt" , "/repo" )
910+
911+ def test_not_logged_in_raises_runtime_error (self , tmp_path ):
912+ """is_error=True with 'not logged in' text raises RuntimeError."""
913+ (tmp_path / "CLAUDE.md" ).write_text ("identity" )
914+ mock_result = MagicMock ()
915+ mock_result .stdout = json .dumps ({"is_error" : True , "result" : "Not logged in · Please run /login" })
916+ mock_result .stderr = ""
917+ mock_result .returncode = 0
918+ backend = CliBackend ()
919+
920+ with patch ("clayde.claude.APP_DIR" , tmp_path ), \
921+ patch ("clayde.claude.get_settings" , return_value = _mock_settings (backend = "cli" )), \
922+ patch ("clayde.claude._resolve_cli_bin" , return_value = "/usr/bin/claude" ), \
923+ patch ("clayde.claude.subprocess.run" , return_value = mock_result ):
924+ with pytest .raises (RuntimeError , match = "authentication failed" ):
925+ backend .invoke ("prompt" , "/repo" )
926+
891927
892928class TestCliBackendIsAvailable :
893929 def test_available_on_success (self ):
@@ -926,6 +962,25 @@ def test_unavailable_on_not_logged_in(self):
926962 patch ("clayde.claude.subprocess.run" , return_value = mock_result ):
927963 assert backend .is_available () is False
928964
965+ def test_unavailable_on_failed_to_authenticate (self ):
966+ mock_result = MagicMock ()
967+ mock_result .stdout = json .dumps ({
968+ "is_error" : True ,
969+ "result" : (
970+ "Failed to authenticate. API Error: 401 "
971+ '{"type":"error","error":{"type":"authentication_error",'
972+ '"message":"Invalid authentication credentials"}}'
973+ ),
974+ })
975+ mock_result .stderr = ""
976+ mock_result .returncode = 0
977+ backend = CliBackend ()
978+
979+ with patch ("clayde.claude.get_settings" , return_value = _mock_settings (backend = "cli" )), \
980+ patch ("clayde.claude._resolve_cli_bin" , return_value = "/usr/bin/claude" ), \
981+ patch ("clayde.claude.subprocess.run" , return_value = mock_result ):
982+ assert backend .is_available () is False
983+
929984 def test_available_on_exception (self ):
930985 backend = CliBackend ()
931986
0 commit comments