Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/exc.py: 68%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# exc.py
2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
8"""Exceptions used with SQLAlchemy.
10The base exception class is :exc:`.SQLAlchemyError`. Exceptions which are
11raised as a result of DBAPI exceptions are all subclasses of
12:exc:`.DBAPIError`.
14"""
15from __future__ import annotations
17import typing
18from typing import Any
19from typing import List
20from typing import Optional
21from typing import overload
22from typing import Tuple
23from typing import Type
24from typing import Union
26from .util import compat
27from .util import preloaded as _preloaded
29if typing.TYPE_CHECKING:
30 from .engine.interfaces import _AnyExecuteParams
31 from .engine.interfaces import Dialect
32 from .sql.compiler import Compiled
33 from .sql.compiler import TypeCompiler
34 from .sql.elements import ClauseElement
36if typing.TYPE_CHECKING:
37 _version_token: str
38else:
39 # set by __init__.py
40 _version_token = None
43class HasDescriptionCode:
44 """helper which adds 'code' as an attribute and '_code_str' as a method"""
46 code: Optional[str] = None
48 def __init__(self, *arg: Any, **kw: Any):
49 code = kw.pop("code", None)
50 if code is not None:
51 self.code = code
52 super().__init__(*arg, **kw)
54 _what_are_we = "error"
56 def _code_str(self) -> str:
57 if not self.code:
58 return ""
59 else:
60 return (
61 f"(Background on this {self._what_are_we} at: "
62 f"https://sqlalche.me/e/{_version_token}/{self.code})"
63 )
65 def __str__(self) -> str:
66 message = super().__str__()
67 if self.code:
68 message = "%s %s" % (message, self._code_str())
69 return message
72class SQLAlchemyError(HasDescriptionCode, Exception):
73 """Generic error class."""
75 def _message(self) -> str:
76 # rules:
77 #
78 # 1. single arg string will usually be a unicode
79 # object, but since __str__() must return unicode, check for
80 # bytestring just in case
81 #
82 # 2. for multiple self.args, this is not a case in current
83 # SQLAlchemy though this is happening in at least one known external
84 # library, call str() which does a repr().
85 #
86 text: str
88 if len(self.args) == 1:
89 arg_text = self.args[0]
91 if isinstance(arg_text, bytes):
92 text = compat.decode_backslashreplace(arg_text, "utf-8")
93 # This is for when the argument is not a string of any sort.
94 # Otherwise, converting this exception to string would fail for
95 # non-string arguments.
96 else:
97 text = str(arg_text)
99 return text
100 else:
101 # this is not a normal case within SQLAlchemy but is here for
102 # compatibility with Exception.args - the str() comes out as
103 # a repr() of the tuple
104 return str(self.args)
106 def _sql_message(self) -> str:
107 message = self._message()
109 if self.code:
110 message = "%s %s" % (message, self._code_str())
112 return message
114 def __str__(self) -> str:
115 return self._sql_message()
118class EmulatedDBAPIException(Exception):
119 """Serves as the base of the DBAPI ``Error`` class for dialects where
120 a DBAPI exception hierrchy needs to be emulated.
122 The current example is the asyncpg dialect.
124 .. versionadded:: 2.1
126 """
128 orig: Exception | None
130 def __init__(self, message: str, orig: Exception | None = None):
131 # we accept None for Exception since all DBAPI.Error objects
132 # need to support construction with a message alone
133 super().__init__(message)
134 self.orig = orig
136 @property
137 def driver_exception(self) -> Exception:
138 """The original driver exception that was raised.
140 This exception object will always originate from outside of
141 SQLAlchemy.
143 """
145 if self.orig is None:
146 raise ValueError(
147 "No original exception is present. Was this "
148 "EmulatedDBAPIException constructed without a driver error?"
149 )
150 return self.orig
152 def __reduce__(self) -> Any:
153 return self.__class__, (self.args[0], self.orig)
156class ArgumentError(SQLAlchemyError):
157 """Raised when an invalid or conflicting function argument is supplied.
159 This error generally corresponds to construction time state errors.
161 """
164class DuplicateColumnError(ArgumentError):
165 """a Column is being added to a Table that would replace another
166 Column, without appropriate parameters to allow this in place.
168 .. versionadded:: 2.0.0b4
170 """
173class ObjectNotExecutableError(ArgumentError):
174 """Raised when an object is passed to .execute() that can't be
175 executed as SQL.
177 """
179 def __init__(self, target: Any):
180 super().__init__(f"Not an executable object: {target!r}")
181 self.target = target
183 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
184 return self.__class__, (self.target,)
187class NoSuchModuleError(ArgumentError):
188 """Raised when a dynamically-loaded module (usually a database dialect)
189 of a particular name cannot be located."""
192class NoForeignKeysError(ArgumentError):
193 """Raised when no foreign keys can be located between two selectables
194 during a join."""
197class AmbiguousForeignKeysError(ArgumentError):
198 """Raised when more than one foreign key matching can be located
199 between two selectables during a join."""
202class ConstraintColumnNotFoundError(ArgumentError):
203 """raised when a constraint refers to a string column name that
204 is not present in the table being constrained.
206 .. versionadded:: 2.0
208 """
211class CircularDependencyError(SQLAlchemyError):
212 """Raised by topological sorts when a circular dependency is detected.
214 There are two scenarios where this error occurs:
216 * In a Session flush operation, if two objects are mutually dependent
217 on each other, they can not be inserted or deleted via INSERT or
218 DELETE statements alone; an UPDATE will be needed to post-associate
219 or pre-deassociate one of the foreign key constrained values.
220 The ``post_update`` flag described at :ref:`post_update` can resolve
221 this cycle.
222 * In a :attr:`_schema.MetaData.sorted_tables` operation, two
223 :class:`_schema.ForeignKey`
224 or :class:`_schema.ForeignKeyConstraint` objects mutually refer to each
225 other. Apply the ``use_alter=True`` flag to one or both,
226 see :ref:`use_alter`.
228 """
230 def __init__(
231 self,
232 message: str,
233 cycles: Any,
234 edges: Any,
235 msg: Optional[str] = None,
236 code: Optional[str] = None,
237 ):
238 if msg is None:
239 message += " (%s)" % ", ".join(repr(s) for s in cycles)
240 else:
241 message = msg
242 SQLAlchemyError.__init__(self, message, code=code)
243 self.cycles = cycles
244 self.edges = edges
246 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
247 return (
248 self.__class__,
249 (None, self.cycles, self.edges, self.args[0]),
250 {"code": self.code} if self.code is not None else {},
251 )
254class CompileError(SQLAlchemyError):
255 """Raised when an error occurs during SQL compilation"""
258class UnsupportedCompilationError(CompileError):
259 """Raised when an operation is not supported by the given compiler.
261 .. seealso::
263 :ref:`faq_sql_expression_string`
265 :ref:`error_l7de`
266 """
268 code = "l7de"
270 def __init__(
271 self,
272 compiler: Union[Compiled, TypeCompiler],
273 element_type: Type[ClauseElement],
274 message: Optional[str] = None,
275 ):
276 super().__init__(
277 "Compiler %r can't render element of type %s%s"
278 % (compiler, element_type, ": %s" % message if message else "")
279 )
280 self.compiler = compiler
281 self.element_type = element_type
282 self.message = message
284 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
285 return self.__class__, (self.compiler, self.element_type, self.message)
288class IdentifierError(SQLAlchemyError):
289 """Raised when a schema name is beyond the max character limit"""
292class DisconnectionError(SQLAlchemyError):
293 """A disconnect is detected on a raw DB-API connection.
295 This error is raised and consumed internally by a connection pool. It can
296 be raised by the :meth:`_events.PoolEvents.checkout`
297 event so that the host pool
298 forces a retry; the exception will be caught three times in a row before
299 the pool gives up and raises :class:`~sqlalchemy.exc.InvalidRequestError`
300 regarding the connection attempt.
302 """
304 invalidate_pool: bool = False
307class InvalidatePoolError(DisconnectionError):
308 """Raised when the connection pool should invalidate all stale connections.
310 A subclass of :class:`_exc.DisconnectionError` that indicates that the
311 disconnect situation encountered on the connection probably means the
312 entire pool should be invalidated, as the database has been restarted.
314 This exception will be handled otherwise the same way as
315 :class:`_exc.DisconnectionError`, allowing three attempts to reconnect
316 before giving up.
318 """
320 invalidate_pool: bool = True
323class TimeoutError(SQLAlchemyError): # noqa
324 """Raised when a connection pool times out on getting a connection."""
327class InvalidRequestError(SQLAlchemyError):
328 """SQLAlchemy was asked to do something it can't do.
330 This error generally corresponds to runtime state errors.
332 """
335class IllegalStateChangeError(InvalidRequestError):
336 """An object that tracks state encountered an illegal state change
337 of some kind.
339 .. versionadded:: 2.0
341 """
344class NoInspectionAvailable(InvalidRequestError):
345 """A subject passed to :func:`sqlalchemy.inspection.inspect` produced
346 no context for inspection."""
349class PendingRollbackError(InvalidRequestError):
350 """A transaction has failed and needs to be rolled back before
351 continuing.
353 .. versionadded:: 1.4
355 """
358class ResourceClosedError(InvalidRequestError):
359 """An operation was requested from a connection, cursor, or other
360 object that's in a closed state."""
363class NoSuchColumnError(InvalidRequestError, KeyError):
364 """A nonexistent column is requested from a ``Row``."""
367class NoResultFound(InvalidRequestError):
368 """A database result was required but none was found.
371 .. versionchanged:: 1.4 This exception is now part of the
372 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
373 remains importable from ``sqlalchemy.orm.exc``.
376 """
379class MultipleResultsFound(InvalidRequestError):
380 """A single database result was required but more than one were found.
382 .. versionchanged:: 1.4 This exception is now part of the
383 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
384 remains importable from ``sqlalchemy.orm.exc``.
387 """
390class NoReferenceError(InvalidRequestError):
391 """Raised by ``ForeignKey`` to indicate a reference cannot be resolved."""
393 table_name: str
396class AwaitRequired(InvalidRequestError):
397 """Error raised by the async greenlet spawn if no async operation
398 was awaited when it required one.
400 """
402 code = "xd1r"
405class MissingGreenlet(InvalidRequestError):
406 r"""Error raised by the async greenlet await\_ if called while not inside
407 the greenlet spawn context.
409 """
411 code = "xd2s"
414class NoReferencedTableError(NoReferenceError):
415 """Raised by ``ForeignKey`` when the referred ``Table`` cannot be
416 located.
418 """
420 def __init__(self, message: str, tname: str):
421 NoReferenceError.__init__(self, message)
422 self.table_name = tname
424 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
425 return self.__class__, (self.args[0], self.table_name)
428class NoReferencedColumnError(NoReferenceError):
429 """Raised by ``ForeignKey`` when the referred ``Column`` cannot be
430 located.
432 """
434 def __init__(self, message: str, tname: str, cname: str):
435 NoReferenceError.__init__(self, message)
436 self.table_name = tname
437 self.column_name = cname
439 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
440 return (
441 self.__class__,
442 (self.args[0], self.table_name, self.column_name),
443 )
446class NoSuchTableError(InvalidRequestError):
447 """Table does not exist or is not visible to a connection."""
450class UnreflectableTableError(InvalidRequestError):
451 """Table exists but can't be reflected for some reason."""
454class UnboundExecutionError(InvalidRequestError):
455 """SQL was attempted without a database connection to execute it on."""
458class DontWrapMixin:
459 """A mixin class which, when applied to a user-defined Exception class,
460 will not be wrapped inside of :exc:`.StatementError` if the error is
461 emitted within the process of executing a statement.
463 E.g.::
465 from sqlalchemy.exc import DontWrapMixin
468 class MyCustomException(Exception, DontWrapMixin):
469 pass
472 class MySpecialType(TypeDecorator):
473 impl = String
475 def process_bind_param(self, value, dialect):
476 if value == "invalid":
477 raise MyCustomException("invalid!")
479 """
482class StatementError(SQLAlchemyError):
483 """An error occurred during execution of a SQL statement.
485 :class:`StatementError` wraps the exception raised
486 during execution, and features :attr:`.statement`
487 and :attr:`.params` attributes which supply context regarding
488 the specifics of the statement which had an issue.
490 The wrapped exception object is available in
491 the :attr:`.orig` attribute.
493 """
495 statement: Optional[str] = None
496 """The string SQL statement being invoked when this exception occurred."""
498 params: Optional[_AnyExecuteParams] = None
499 """The parameter list being used when this exception occurred."""
501 orig: Optional[BaseException] = None
502 """The original exception that was thrown.
504 .. seealso::
506 :attr:`.DBAPIError.driver_exception` - a more specific attribute that
507 is guaranteed to return the exception object raised by the third
508 party driver in use, even when using asyncio.
510 """
512 ismulti: Optional[bool] = None
513 """multi parameter passed to repr_params(). None is meaningful."""
515 connection_invalidated: bool = False
517 def __init__(
518 self,
519 message: str,
520 statement: Optional[str],
521 params: Optional[_AnyExecuteParams],
522 orig: Optional[BaseException],
523 hide_parameters: bool = False,
524 code: Optional[str] = None,
525 ismulti: Optional[bool] = None,
526 ):
527 SQLAlchemyError.__init__(self, message, code=code)
528 self.statement = statement
529 self.params = params
530 self.orig = orig
531 self.ismulti = ismulti
532 self.hide_parameters = hide_parameters
533 self.detail: List[str] = []
535 def add_detail(self, msg: str) -> None:
536 self.detail.append(msg)
538 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
539 return (
540 self.__class__,
541 (
542 self.args[0],
543 self.statement,
544 self.params,
545 self.orig,
546 self.hide_parameters,
547 self.__dict__.get("code"),
548 self.ismulti,
549 ),
550 {"detail": self.detail},
551 )
553 @_preloaded.preload_module("sqlalchemy.sql.util")
554 def _sql_message(self) -> str:
555 util = _preloaded.sql_util
557 details = [self._message()]
558 if self.statement:
559 stmt_detail = "[SQL: %s]" % self.statement
560 details.append(stmt_detail)
561 if self.params:
562 if self.hide_parameters:
563 details.append(
564 "[SQL parameters hidden due to hide_parameters=True]"
565 )
566 else:
567 params_repr = util._repr_params(
568 self.params, 10, ismulti=self.ismulti
569 )
570 details.append("[parameters: %r]" % params_repr)
571 code_str = self._code_str()
572 if code_str:
573 details.append(code_str)
574 return "\n".join(["(%s)" % det for det in self.detail] + details)
577class DBAPIError(StatementError):
578 """Raised when the execution of a database operation fails.
580 Wraps exceptions raised by the DB-API underlying the
581 database operation. Driver-specific implementations of the standard
582 DB-API exception types are wrapped by matching sub-types of SQLAlchemy's
583 :class:`DBAPIError` when possible. DB-API's ``Error`` type maps to
584 :class:`DBAPIError` in SQLAlchemy, otherwise the names are identical. Note
585 that there is no guarantee that different DB-API implementations will
586 raise the same exception type for any given error condition.
588 :class:`DBAPIError` features :attr:`~.StatementError.statement`
589 and :attr:`~.StatementError.params` attributes which supply context
590 regarding the specifics of the statement which had an issue, for the
591 typical case when the error was raised within the context of
592 emitting a SQL statement.
594 The wrapped exception object is available in the
595 :attr:`~.StatementError.orig` attribute. Its type and properties are
596 DB-API implementation specific.
598 """
600 code = "dbapi"
602 orig: Optional[Exception]
604 @overload
605 @classmethod
606 def instance(
607 cls,
608 statement: Optional[str],
609 params: Optional[_AnyExecuteParams],
610 orig: Exception,
611 dbapi_base_err: Type[Exception],
612 hide_parameters: bool = False,
613 connection_invalidated: bool = False,
614 dialect: Optional[Dialect] = None,
615 ismulti: Optional[bool] = None,
616 ) -> StatementError: ...
618 @overload
619 @classmethod
620 def instance(
621 cls,
622 statement: Optional[str],
623 params: Optional[_AnyExecuteParams],
624 orig: DontWrapMixin,
625 dbapi_base_err: Type[Exception],
626 hide_parameters: bool = False,
627 connection_invalidated: bool = False,
628 dialect: Optional[Dialect] = None,
629 ismulti: Optional[bool] = None,
630 ) -> DontWrapMixin: ...
632 @overload
633 @classmethod
634 def instance(
635 cls,
636 statement: Optional[str],
637 params: Optional[_AnyExecuteParams],
638 orig: BaseException,
639 dbapi_base_err: Type[Exception],
640 hide_parameters: bool = False,
641 connection_invalidated: bool = False,
642 dialect: Optional[Dialect] = None,
643 ismulti: Optional[bool] = None,
644 ) -> BaseException: ...
646 @classmethod
647 def instance(
648 cls,
649 statement: Optional[str],
650 params: Optional[_AnyExecuteParams],
651 orig: Union[BaseException, DontWrapMixin],
652 dbapi_base_err: Type[Exception],
653 hide_parameters: bool = False,
654 connection_invalidated: bool = False,
655 dialect: Optional[Dialect] = None,
656 ismulti: Optional[bool] = None,
657 ) -> Union[BaseException, DontWrapMixin]:
658 # Don't ever wrap these, just return them directly as if
659 # DBAPIError didn't exist.
660 if (
661 isinstance(orig, BaseException) and not isinstance(orig, Exception)
662 ) or isinstance(orig, DontWrapMixin):
663 return orig
665 if orig is not None:
666 # not a DBAPI error, statement is present.
667 # raise a StatementError
668 if isinstance(orig, SQLAlchemyError) and statement:
669 return StatementError(
670 "(%s.%s) %s"
671 % (
672 orig.__class__.__module__,
673 orig.__class__.__name__,
674 orig.args[0],
675 ),
676 statement,
677 params,
678 orig,
679 hide_parameters=hide_parameters,
680 code=orig.code,
681 ismulti=ismulti,
682 )
683 elif not isinstance(orig, dbapi_base_err) and statement:
684 return StatementError(
685 "(%s.%s) %s"
686 % (
687 orig.__class__.__module__,
688 orig.__class__.__name__,
689 orig,
690 ),
691 statement,
692 params,
693 orig,
694 hide_parameters=hide_parameters,
695 ismulti=ismulti,
696 )
698 glob = globals()
699 for super_ in orig.__class__.__mro__:
700 name = super_.__name__
701 if dialect:
702 name = dialect.dbapi_exception_translation_map.get(
703 name, name
704 )
705 if name in glob and issubclass(glob[name], DBAPIError):
706 cls = glob[name]
707 break
709 return cls(
710 statement,
711 params,
712 orig,
713 connection_invalidated=connection_invalidated,
714 hide_parameters=hide_parameters,
715 code=cls.code,
716 ismulti=ismulti,
717 )
719 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
720 return (
721 self.__class__,
722 (
723 self.statement,
724 self.params,
725 self.orig,
726 self.hide_parameters,
727 self.connection_invalidated,
728 self.__dict__.get("code"),
729 self.ismulti,
730 ),
731 {"detail": self.detail},
732 )
734 def __init__(
735 self,
736 statement: Optional[str],
737 params: Optional[_AnyExecuteParams],
738 orig: BaseException,
739 hide_parameters: bool = False,
740 connection_invalidated: bool = False,
741 code: Optional[str] = None,
742 ismulti: Optional[bool] = None,
743 ):
744 try:
745 text = str(orig)
746 except Exception as e:
747 text = "Error in str() of DB-API-generated exception: " + str(e)
748 StatementError.__init__(
749 self,
750 "(%s.%s) %s"
751 % (orig.__class__.__module__, orig.__class__.__name__, text),
752 statement,
753 params,
754 orig,
755 hide_parameters,
756 code=code,
757 ismulti=ismulti,
758 )
759 self.connection_invalidated = connection_invalidated
761 @property
762 def driver_exception(self) -> Exception:
763 """The exception object originating from the driver (DBAPI) outside
764 of SQLAlchemy.
766 In the case of some asyncio dialects, special steps are taken to
767 resolve the exception to what the third party driver has raised, even
768 for SQLAlchemy dialects that include an "emulated" DBAPI exception
769 hierarchy.
771 For non-asyncio dialects, this attribute will be the same attribute
772 as the :attr:`.StatementError.orig` attribute.
774 For an asyncio dialect provided by SQLAlchemy, depending on if the
775 dialect provides an "emulated" exception hierarchy or if the underlying
776 DBAPI raises DBAPI-style exceptions, it will refer to either the
777 :attr:`.EmulatedDBAPIException.driver_exception` attribute on the
778 :class:`.EmulatedDBAPIException` that's thrown (such as when using
779 asyncpg), or to the actual exception object thrown by the
780 third party driver.
782 .. versionadded:: 2.1
784 """
786 if self.orig is None:
787 raise ValueError(
788 "No original exception is present. Was this "
789 "DBAPIError constructed without a driver error?"
790 )
792 if isinstance(self.orig, EmulatedDBAPIException):
793 return self.orig.driver_exception
794 else:
795 return self.orig
798class InterfaceError(DBAPIError):
799 """Wraps a DB-API InterfaceError."""
801 code = "rvf5"
804class DatabaseError(DBAPIError):
805 """Wraps a DB-API DatabaseError."""
807 code = "4xp6"
810class DataError(DatabaseError):
811 """Wraps a DB-API DataError."""
813 code = "9h9h"
816class OperationalError(DatabaseError):
817 """Wraps a DB-API OperationalError."""
819 code = "e3q8"
822class IntegrityError(DatabaseError):
823 """Wraps a DB-API IntegrityError."""
825 code = "gkpj"
828class InternalError(DatabaseError):
829 """Wraps a DB-API InternalError."""
831 code = "2j85"
834class ProgrammingError(DatabaseError):
835 """Wraps a DB-API ProgrammingError."""
837 code = "f405"
840class NotSupportedError(DatabaseError):
841 """Wraps a DB-API NotSupportedError."""
843 code = "tw8g"
846# Warnings
849class SATestSuiteWarning(Warning):
850 """warning for a condition detected during tests that is non-fatal
852 Currently outside of SAWarning so that we can work around tools like
853 Alembic doing the wrong thing with warnings.
855 """
858class SADeprecationWarning(HasDescriptionCode, DeprecationWarning):
859 """Issued for usage of deprecated APIs."""
861 deprecated_since: Optional[str] = None
862 "Indicates the version that started raising this deprecation warning"
865class Base20DeprecationWarning(SADeprecationWarning):
866 """Issued for usage of APIs specifically deprecated or legacy in
867 SQLAlchemy 2.0.
869 .. seealso::
871 :ref:`error_b8d9`.
873 :ref:`deprecation_20_mode`
875 """
877 deprecated_since: Optional[str] = "1.4"
878 "Indicates the version that started raising this deprecation warning"
880 def __str__(self) -> str:
881 return (
882 super().__str__()
883 + " (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)"
884 )
887class LegacyAPIWarning(Base20DeprecationWarning):
888 """indicates an API that is in 'legacy' status, a long term deprecation."""
891class MovedIn20Warning(Base20DeprecationWarning):
892 """Subtype of Base20DeprecationWarning to indicate an API that moved
893 only.
894 """
897class SAPendingDeprecationWarning(PendingDeprecationWarning):
898 """A similar warning as :class:`_exc.SADeprecationWarning`, this warning
899 is not used in modern versions of SQLAlchemy.
901 """
903 deprecated_since: Optional[str] = None
904 "Indicates the version that started raising this deprecation warning"
907class SAWarning(HasDescriptionCode, RuntimeWarning):
908 """Issued at runtime."""
910 _what_are_we = "warning"