#
# (C) Pywikibot team, 2008-2026
#
# Distributed under the terms of the MIT license.
#
"""**Pywikibot Exceptions** and warning classes.
This module contains all exception and warning classes used throughout
the framework::
Exception
└── Error
├── APIError
| ├── APIMWError
| └── UploadError
├── AutoblockUserError
├── CaptchaError
├── CitoidError
├── ClientError
| └── Client414Error
├── InvalidTitleError
├── NoUsernameError
├── PageInUseError
├── PageRelatedError
| ├── CircularRedirectError
| ├── InterwikiRedirectPageError
| ├── IsNotRedirectPageError
| ├── IsRedirectPageError
| ├── NoMoveTargetError
| ├── NoPageError
| ├── NoRenameTargetError
| ├── NotEmailableError
| ├── PageLoadRelatedError
| | ├── InconsistentTitleError
| | ├── InvalidPageError
| | └── NoSiteLinkError
| ├── PageSaveRelatedError
| | ├── EditConflictError
| | | ├── ArticleExistsConflictError
| | | ├── PageCreatedConflictError
| | | └── PageDeletedConflictError
| | ├── LockedPageError
| | | ├── LockedNoPageError
| | | └── CascadeLockedPageError
| | ├── NoCreateError
| | ├── OtherPageSaveError
| | ├── SpamblacklistError
| | ├── TitleblacklistError
| | └── AbuseFilterDisallowedError
| └── UnsupportedPageError
├── SectionError
├── ServerError
| ├── FatalServerError
| └── Server504Error
├── SiteDefinitionError
| ├── UnknownFamilyError
| └── UnknownSiteError
├── ApiTimeoutError
| └── MaxlagTimeoutError
├── TranslationError
├── UnexpectedAPIDataError (ValueError)
├── UnknownExtensionError (NotImplementedError)
├── UserRightsError
| └── HiddenKeyError (KeyError)
├── VersionParseError
└── WikiBaseError
├── CoordinateGlobeUnknownError (NotImplementedError)
├── EntityTypeUnknownError
└── NoWikibaseEntityError
UserWarning
├── ArgumentDeprecationWarning (FutureWarning)
└── FamilyMaintenanceWarning
RuntimeWarning
└── NotImplementedWarning
Error: Base class, all exceptions should the subclass of this class.
- CaptchaError: Captcha is asked and config.solve_captcha == False
- AutoblockUserError: requested action on a virtual autoblock user not valid
- InvalidTitleError: Invalid page title
- NoUsernameError: Username is not in user config file, or it is invalid.
- PageInUseError: Page cannot be reserved due to a lock
- SectionError: The section specified by # does not exist
- TranslationError: no language translation found, i18n/l10n message
not available
- UnexpectedAPIDataError: API data contains unexpected fields or values
- UnknownExtensionError: Extension is not defined for this site
- UserRightsError: insufficient rights for requested action
- VersionParseError: failed to parse version information
APIError: wiki API returned an error
- APIMWError: MediaWiki internal exception
- UploadError: upload failed
SiteDefinitionError: Site loading problem
- UnknownSiteError: Site does not exist in Family
- UnknownFamilyError: Family is not registered
PageRelatedError: any exception which is caused by an operation on a Page.
- NoPageError: Page does not exist
- UnsupportedPageError: Page is not supported due to a namespace restriction
- IsRedirectPageError: Page is a redirect page
- IsNotRedirectPageError: Page is not a redirect page
- CircularRedirectError: Page is a circular redirect
- InterwikiRedirectPageError: Page is a redirect to another site
- InvalidPageError: Page is invalid e.g. without history
- NotEmailableError: The target user has disabled email
- NoMoveTargetError: An expected move target page does not exist
- NoRenameTargetError: An expected rename target user does not exist
PageLoadRelatedError: any exception which happens while loading a Page.
- InconsistentTitleError: Page receives a title inconsistent with query
- NoSiteLinkError: ItemPage has no sitelink to given site
PageSaveRelatedError: page exceptions within the save operation on a Page
- AbuseFilterDisallowedError: AbuseFilter disallowed
- SpamblacklistError: MediaWiki spam filter detected a blacklisted URL
- TitleblacklistError: MediaWiki detected a blacklisted page title
- OtherPageSaveError: misc. other save related exception.
- LockedPageError: Page is locked
- LockedNoPageError: Title is locked against creation
- CascadeLockedPageError: Page is locked due to cascading protection
- EditConflictError: Edit conflict while uploading the page
- PageDeletedConflictError: Page was deleted since being retrieved
- PageCreatedConflictError: Page was created by another user
- ArticleExistsConflictError: Page article already exists
- NoCreateError: parameter nocreate not allow page creation
ServerError: a problem with the server.
- FatalServerError: A fatal/non-recoverable server error
- Server504Error: Server timed out with HTTP 504 code
ClientError: A problem with the client request
- Client414Error: HTTP 414 code - URI too long
WikiBaseError: any issue specific to Wikibase.
- NoWikibaseEntityError: entity doesn't exist
- CoordinateGlobeUnknownError: globe is not implemented yet.
- EntityTypeUnknownError: entity type is not available on the site.
ApiTimeoutError: request failed with a timeout
- MaxlagTimeoutError: request failed with a maxlag timeout
DeprecationWarning: old functionality replaced by new functionality
PendingDeprecationWarning: problematic code which has not yet been
fully deprecated, possibly because a replacement is not available
RuntimeWarning: problems developers should have fixed, and users need to
be aware of its status.
- NotImplementedWarning: functionality not implemented
UserWarning: warnings targeted at users
- config._ConfigurationDeprecationWarning: user configuration file problems
- login._PasswordFileWarning: password file problems
- ArgumentDeprecationWarning: command line argument problems
- FamilyMaintenanceWarning: missing information in family definition
.. version-changed:: 6.0
exceptions were renamed and are ending with "Error".
.. version-changed:: 7.0
All Pywikibot Error exceptions must be imported from
``pywikibot.exceptions``. Deprecated exceptions identifiers were
removed.
.. version-changed:: 8.1
``Server414Error`` class is deprecated; use :class:`Client414Error`
instead.
.. version-changed:: 11.6
:exc:`UnexpectedAPIDataError` was added.
"""
from __future__ import annotations
import re
from typing import Any
import pywikibot
from pywikibot.tools._deprecate import (
ModuleDeprecationWrapper,
_NotImplementedWarning,
)
[docs]
class NotImplementedWarning(_NotImplementedWarning):
"""Feature that is no longer implemented."""
[docs]
class ArgumentDeprecationWarning(UserWarning, FutureWarning):
"""Command line argument that is no longer supported."""
[docs]
class FamilyMaintenanceWarning(UserWarning):
"""Family class is missing definitions."""
[docs]
class Error(Exception):
"""Pywikibot error."""
def __init__(self, arg: Exception | str) -> None:
"""Initializer."""
self.unicode = str(arg)
def __str__(self) -> str:
"""Return a string representation."""
return self.unicode
[docs]
class APIError(Error):
"""The wiki site returned an error message."""
def __init__(self, code: str, info: str, **kwargs: Any) -> None:
"""Save error dict returned by MW API."""
self.code = code
self.info = info
self.other = kwargs
self.unicode = str(self)
def __repr__(self) -> str:
"""Return internal representation."""
return '{name}("{code}", "{info}", {other})'.format(
name=self.__class__.__name__, **self.__dict__)
def __str__(self) -> str:
"""Return a string representation."""
if self.other:
return '{}: {}\n[{}]'.format(
self.code,
self.info,
';\n '.join(
f'{key}: {val}'
for key, val in self.other.items()))
return f'{self.code}: {self.info}'
[docs]
class APIMWError(APIError):
"""The API site returned an error about a MediaWiki internal exception."""
def __init__(self, mediawiki_exception_class_name: str, info: str,
**kwargs: Any) -> None:
"""Save error dict returned by MW API."""
self.mediawiki_exception_class_name = mediawiki_exception_class_name
code = 'internal_api_error_' + mediawiki_exception_class_name
super().__init__(code, info, **kwargs)
[docs]
class UploadError(APIError):
"""Upload failed with a warning message (passed as the argument)."""
def __init__(self, code: str, message: str,
file_key: str | None = None,
offset: int | bool = 0) -> None:
"""Create a new UploadError instance.
:param file_key: The file_key of the uploaded file to reuse it
later. If no key is known or it is an incomplete file it may
be None.
:param offset: The starting offset for a chunked upload. Is
False when there is no offset.
"""
super().__init__(code, message)
self.file_key = file_key
self.offset = offset
@property
def message(self) -> str:
"""Return warning message."""
return self.info
[docs]
class CitoidError(Error):
"""The Citoid service returned an error.
.. version-added:: 11.7
"""
[docs]
class PageSaveRelatedError(PageRelatedError):
"""Saving the page has failed."""
message = 'Page {} was not saved.'
[docs]
class OtherPageSaveError(PageSaveRelatedError):
"""Saving the page has failed due to uncatchable error."""
message = 'Edit to page {title} failed:\n{reason}'
def __init__(self, page: pywikibot.page.BasePage,
reason: str | Exception) -> None:
"""Initializer.
:param reason: Details of the problem
"""
self.reason = reason
super().__init__(page)
@property
def args(self) -> str: # type: ignore[override]
"""Expose args."""
return str(self.reason)
[docs]
class NoUsernameError(Error):
"""Username is not in user config file (user-config.py)."""
[docs]
class NoPageError(PageRelatedError):
"""Page does not exist."""
message = "Page {} doesn't exist."
[docs]
class UnsupportedPageError(PageRelatedError):
"""Unsupported page due to namespace restriction."""
# namespaces < 0 aren't supported (T169213)
message = 'Page {} is not supported due to namespace restriction.'
[docs]
class NoMoveTargetError(PageRelatedError):
"""Expected move target page not found."""
message = 'Move target page of {} not found.'
[docs]
class PageLoadRelatedError(PageRelatedError):
"""Loading the contents of a Page object has failed."""
message = 'Page {} was not loaded.'
[docs]
class InconsistentTitleError(PageLoadRelatedError):
"""Page receives a title inconsistent with query."""
def __init__(self, page: pywikibot.page.BasePage, actual: str) -> None:
"""Initializer.
:param page: Page that caused the exception
:param actual: title obtained by query
"""
self.message = f"Query on {{}} returned data on '{actual}'"
super().__init__(page)
[docs]
class NoSiteLinkError(PageLoadRelatedError):
"""ItemPage has no sitelink to the given site.
.. version-added:: 8.1
.. version-deprecated:: 8.1
This exception depends on :exc:`NoPageError` but it will be
removed.
.. version-removed:: 11.0
Dependency on :exc:`NoPageError` was removed.
"""
def __init__(self, page: pywikibot.page.ItemPage, dbname: str) -> None:
"""Initializer.
:param page: ItemPage that caused the exception.
:param dbname: site identifier of the queried sitelink.
"""
self.message = f'Item {{}} has no sitelink to {dbname!r}'
super().__init__(page)
[docs]
class SiteDefinitionError(Error):
"""Site does not exist."""
[docs]
class UnknownSiteError(SiteDefinitionError):
"""Site does not exist in Family."""
[docs]
class UnknownFamilyError(SiteDefinitionError):
"""Family is not registered."""
[docs]
class UnexpectedAPIDataError(Error, ValueError):
"""Raised when API data contains unexpected fields or values.
.. version-added:: 11.6
"""
[docs]
class UnknownExtensionError(Error, NotImplementedError):
"""Extension is not defined."""
[docs]
class VersionParseError(Error):
"""Failed to parse version information."""
[docs]
class IsRedirectPageError(PageRelatedError):
"""Page is a redirect page."""
message = 'Page {} is a redirect page.'
[docs]
class IsNotRedirectPageError(PageRelatedError):
"""Page is not a redirect page."""
message = 'Page {} is not a redirect page.'
[docs]
class CircularRedirectError(PageRelatedError):
"""Page is a circular redirect.
Exception argument is the redirect target; this may be the same
title as this page or a different title (in which case the target
page directly or indirectly redirects back to this one)
"""
message = 'Page {} is a circular redirect.'
[docs]
class InterwikiRedirectPageError(PageRelatedError):
"""Page is a redirect to another site.
This is considered invalid in Pywikibot. See bug :phab:`T75184`.
"""
message = ('Page redirects to a page on another Site.\n'
'Page: {page}\n'
'Target page: {target_page} on {target_site}.')
def __init__(self, page: pywikibot.page.BasePage,
target_page: pywikibot.page.BasePage) -> None:
"""Initializer.
:param target_page: Target page of the redirect.
"""
self.target_page = target_page
self.target_site = target_page.site
super().__init__(page)
[docs]
class InvalidPageError(PageLoadRelatedError):
"""Missing page history.
.. version-added:: 6.2
"""
message = 'Page {} is invalid.'
[docs]
class InvalidTitleError(Error):
"""Invalid page title."""
[docs]
class LockedPageError(PageSaveRelatedError):
"""Page is locked."""
message = 'Page {} is locked.'
[docs]
class LockedNoPageError(LockedPageError):
"""Title is locked against creation."""
message = 'Page {} does not exist and is locked preventing creation.'
[docs]
class CascadeLockedPageError(LockedPageError):
"""Page is locked due to cascading protection."""
message = 'Page {} is locked due to cascading protection.'
[docs]
class SectionError(Error):
"""The section specified by # does not exist."""
[docs]
class NoCreateError(PageSaveRelatedError):
"""Parameter nocreate doesn't allow page creation."""
message = 'Page {} could not be created due to parameter nocreate'
[docs]
class EditConflictError(PageSaveRelatedError):
"""There has been an edit conflict while uploading the page."""
message = 'Page {} could not be saved due to an edit conflict'
[docs]
class PageDeletedConflictError(EditConflictError):
"""Page was deleted since being retrieved."""
message = 'Page {} has been deleted since last retrieved.'
[docs]
class PageCreatedConflictError(EditConflictError):
"""Page was created by another user."""
message = 'Page {} has been created since last retrieved.'
[docs]
class ArticleExistsConflictError(EditConflictError):
"""Page already exists."""
message = ('Destination article {} already exists and is not a redirect '
'to the source article')
[docs]
class AbuseFilterDisallowedError(PageSaveRelatedError):
"""Page save failed because the AbuseFilter disallowed it."""
message = ('Edit to page {title} disallowed by the AbuseFilter.\n'
'{info}')
def __init__(self, page: pywikibot.page.BasePage, info: str) -> None:
"""Initializer."""
self.info = info
super().__init__(page)
[docs]
class SpamblacklistError(PageSaveRelatedError):
"""Page save failed because MediaWiki detected a blacklisted spam URL."""
message = ('Edit to page {title} rejected by spam filter due to '
'content:\n{url}')
def __init__(self, page: pywikibot.page.BasePage, url: str) -> None:
"""Initializer."""
self.url = url
super().__init__(page)
[docs]
class TitleblacklistError(PageSaveRelatedError):
"""Page save failed because MediaWiki detected a blacklisted page title."""
message = 'Page {} is title-blacklisted.'
[docs]
class ClientError(Error):
"""Got unexpected server response due to client issue.
.. version-added:: 8.1
"""
[docs]
class Client414Error(ClientError):
"""Server returned with HTTP 414 code.
.. version-added:: 8.1
"""
[docs]
class ServerError(Error):
"""Got unexpected server response."""
[docs]
class FatalServerError(ServerError):
"""A fatal server error will not be corrected by resending the request."""
[docs]
class Server504Error(ServerError):
"""Server timed out with HTTP 504 code."""
[docs]
class CaptchaError(Error):
"""Captcha is asked and config.solve_captcha == False."""
[docs]
class AutoblockUserError(Error):
"""Requested action on a virtual autoblock user not valid.
The class AutoblockUserError is an exception that is raised whenever
an action is requested on a virtual autoblock user that's not
available for him (i.e. roughly everything except unblock).
"""
[docs]
class TranslationError(Error, ImportError):
"""Raised when no correct translation could be found.
Inherits from ImportError, as this exception is now used where
previously an ImportError would have been raised, and may have been
caught by scripts as such.
"""
[docs]
class UserRightsError(Error):
"""Insufficient user rights to perform an action."""
[docs]
class HiddenKeyError(UserRightsError, KeyError):
"""Insufficient user rights to view the hidden key."""
[docs]
class NotEmailableError(PageRelatedError):
"""This user is not emailable."""
message = '{} is not emailable.'
[docs]
class PageInUseError(Error):
"""Page cannot be reserved for writing due to existing lock."""
[docs]
class WikiBaseError(Error):
"""Wikibase related error."""
[docs]
class NoWikibaseEntityError(WikiBaseError):
"""This entity doesn't exist."""
def __init__(self, entity: pywikibot.page.WikibaseEntity) -> None:
"""Initializer.
:param entity: Wikibase entity
"""
super().__init__(
f"Entity '{entity.id}' doesn't exist on {entity.repo}")
self.entity = entity
[docs]
class CoordinateGlobeUnknownError(WikiBaseError, NotImplementedError):
"""This globe is not implemented yet in either WikiBase or pywikibot."""
[docs]
class EntityTypeUnknownError(WikiBaseError):
"""The requested entity type is not recognised on this site."""
[docs]
class ApiTimeoutError(Error):
"""Request failed with a timeout error.
.. version-changed:: 11.5
:exc:`TimeoutError` was renamed to :exc:`ApiTimeoutError`
.. version-changed:: 11.7
The *site* and *uri* attributes and parameters were added.
:param args: Arguments passed to the base exception.
:param site: Site associated with the failed request, if available.
:param uri: URI associated with the failed request, if available.
"""
def __init__(
self,
*args: Exception | str,
site: pywikibot.site.BaseSite | None = None,
uri: str | None = None
) -> None:
"""Initializer."""
super().__init__(*args)
#: Site associated with the failed request.
self.site = site
#: URI associated with the failed request.
self.uri = uri
def __repr__(self) -> str:
"""Return a detailed representation of the exception."""
args = ', '.join(repr(arg) for arg in self.args)
if self.site is not None:
args += f', site={self.site!r}'
if self.uri is not None:
args += f', uri={self.uri!r}'
return f'{type(self).__name__}({args})'
[docs]
class MaxlagTimeoutError(ApiTimeoutError):
"""Request failed with a maxlag timeout error."""
[docs]
class ApiNotAvailableError(Error):
"""API is not available, e.g. due to a network error or configuration."""
wrapper = ModuleDeprecationWrapper(__name__)
wrapper.add_deprecated_attr(
'TimeoutError',
replacement=ApiTimeoutError,
since='11.5.0',
)