Skip to content

Errors

Every error socialchimp raises is a SocialChimpError. Catch that one if you only want to know something went wrong; catch a specific subclass if your app needs to react differently - retry, ask the person to sign in again, or show them what the network actually said.

ConfigError and InvalidPostError are a ValueError as well. Both are raised for a value your code handed us, and both were a bare ValueError before 0.3.0, so code written against that still works. Catch SocialChimpError; you do not need to catch both.

SocialChimpError

SocialChimpError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: Exception

Base for everything socialchimp raises.

Catch this to catch every problem socialchimp reports, whichever network caused it.

Attributes:

Name Type Description
platform

Which network this came from, when it came from one. None for problems on your own side, such as ConfigError.

raw dict[str, Any]

The network's untouched reply, when there was one. Empty otherwise. Look here for anything socialchimp did not model.

Record the message, and where it came from.

Parameters:

Name Type Description Default
message str

What happened, in plain words.

required
platform str | None

Which network complained, if any.

None
raw dict[str, Any] | None

The network's untouched reply, if there was one.

None
Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

Setting things up

ConfigError

ConfigError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError, ValueError

Something is set up wrong on your side.

Missing credentials, an unknown platform name, a datetime with no timezone, a storage class that does not do what it promised. These are bugs to fix, not conditions to retry.

Also a ValueError, because it is raised for a value your code handed us. See the comment above.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

Signing in and tokens

AuthError

AuthError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

The network would not accept who we say we are.

Usually the person needs to connect their account again.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

TokenExpiredError

TokenExpiredError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: AuthError

The token ran out and could not be renewed.

socialchimp renews tokens for you. Seeing this means renewal was not possible - the network has no refresh token, or the refresh token itself expired or was revoked. The person has to sign in again.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

What the network would not do

NotAllowedError

NotAllowedError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

The account is real but is not permitted to do this.

Nearly always a missing permission. Ask for the right one when the person connects their account.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

MissingPermissionError

MissingPermissionError(
    *,
    needs: str,
    suggestion: str | None = None,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: NotAllowedError

The account is missing one specific permission.

More precise than a plain NotAllowedError: this names the permission that is missing, so an app can tell someone exactly what to grant rather than only that something was refused.

Attributes:

Name Type Description
needs

The permission that is missing, in plain words - "push", "direct messages".

suggestion

What to do about it, when there is something worth saying beyond reconnecting - Bluesky's app passwords cannot have a permission added after the fact, so a new one has to be made. None when there is nothing more to add.

Build a message naming the permission that is missing.

Parameters:

Name Type Description Default
needs str

The permission that is missing.

required
suggestion str | None

What to do about it, written as a whole sentence. It is added after the first one.

None
platform str | None

Which network refused it, if any.

None
raw dict[str, Any] | None

The network's untouched reply, if there was one.

None
Source code in src/socialchimp/errors.py
def __init__(
    self,
    *,
    needs: str,
    suggestion: str | None = None,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Build a message naming the permission that is missing.

    Args:
        needs: The permission that is missing.
        suggestion: What to do about it, written as a whole sentence. It
            is added after the first one.
        platform: Which network refused it, if any.
        raw: The network's untouched reply, if there was one.
    """
    message = f"This connection is missing the {needs} permission."
    if suggestion is not None:
        message = f"{message} {suggestion}"
    super().__init__(message, platform=platform, raw=raw)
    self.needs = needs
    self.suggestion = suggestion

BlockedError

BlockedError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: NotAllowedError

The other person blocked us, or we blocked them.

Either way there is nothing to retry: the block has to be undone by a person, on the network itself, before this will work.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

ReplyWindowClosedError

ReplyWindowClosedError(
    message: str,
    *,
    closed_at: datetime | None = None,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: NotAllowedError

Too long has passed to reply to this conversation.

Meta gives 24 hours after somebody messages a page to reply for free; after that, sending one back is refused until they write again.

Attributes:

Name Type Description
closed_at

When the window closed, when the network says. None when it does not say.

Keep when the window closed alongside the message.

Parameters:

Name Type Description Default
message str

What happened.

required
closed_at datetime | None

When the window closed, if the network said.

None
platform str | None

Which network refused the reply.

None
raw dict[str, Any] | None

The network's untouched reply.

None
Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    closed_at: datetime | None = None,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Keep when the window closed alongside the message.

    Args:
        message: What happened.
        closed_at: When the window closed, if the network said.
        platform: Which network refused the reply.
        raw: The network's untouched reply.
    """
    super().__init__(message, platform=platform, raw=raw)
    self.closed_at = closed_at

NotFoundError

NotFoundError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

The post, account or page asked for does not exist.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

PostGoneError

PostGoneError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: NotFoundError

The post or comment asked for was deleted, or never existed.

More precise than a plain NotFoundError for the one thing that is asked for by id constantly: a post to reply to, to like, to read the thread of. Somebody deleted it, or it was never theirs to find.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

RateLimitError

RateLimitError(
    message: str,
    *,
    retry_after: float | None = None,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

The network is asking us to slow down.

Attributes:

Name Type Description
retry_after

Seconds to wait before trying again, when the network tells us. None when it does not.

Store the wait time alongside the message.

Parameters:

Name Type Description Default
message str

What happened.

required
retry_after float | None

Seconds to wait, if the network said.

None
platform str | None

Which network is asking us to slow down.

None
raw dict[str, Any] | None

The network's untouched reply.

None
Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    retry_after: float | None = None,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Store the wait time alongside the message.

    Args:
        message: What happened.
        retry_after: Seconds to wait, if the network said.
        platform: Which network is asking us to slow down.
        raw: The network's untouched reply.
    """
    super().__init__(message, platform=platform, raw=raw)
    self.retry_after = retry_after

InvalidPostError

InvalidPostError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError, ValueError

The post breaks a rule of the network it was going to.

Text too long, too many pictures, a missing setting that network needs. socialchimp raises this before sending where it can, so you get a clear message instead of the network's error code.

Also raised for a post no network would take - one with neither text nor media - and for a picture or video that cannot be read, such as one that is only a web address on a network that will not fetch it.

Also a ValueError, because it is raised for a value your code handed us. See the comment above ConfigError.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

NotSupportedError

NotSupportedError(
    *,
    platform: str,
    what: str,
    suggestion: str | None = None,
)

Bases: SocialChimpError

This network genuinely cannot do that.

Not a gap in socialchimp - a gap in the network. Bluesky has no scheduling; YouTube has no text-only post. Rather than quietly doing something else, we say so.

Attributes:

Name Type Description
platform

The network that cannot do it.

what

The thing it cannot do, in plain words.

suggestion

What to do instead, when there is something. None when the answer really is just "not here".

Build a message naming both the network and the missing feature.

Parameters:

Name Type Description Default
platform str

The network that cannot do it.

required
what str

The thing it cannot do. Keep it to a phrase that finishes "pinterest does not support ..." - anything longer belongs in suggestion, or the first sentence runs on for a paragraph and nobody reads the end of it.

required
suggestion str | None

What to do instead, written as whole sentences. It is added after the first one.

None
Source code in src/socialchimp/errors.py
def __init__(
    self,
    *,
    platform: str,
    what: str,
    suggestion: str | None = None,
) -> None:
    """Build a message naming both the network and the missing feature.

    Args:
        platform: The network that cannot do it.
        what: The thing it cannot do. Keep it to a phrase that finishes
            "pinterest does not support ..." - anything longer belongs
            in `suggestion`, or the first sentence runs on for a
            paragraph and nobody reads the end of it.
        suggestion: What to do instead, written as whole sentences. It
            is added after the first one.
    """
    message = f"{platform} does not support {what}."
    if suggestion is not None:
        message = f"{message} {suggestion}"
    super().__init__(message, platform=platform)
    self.what = what
    self.suggestion = suggestion

Talking to the network

NetworkError

NetworkError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

We could not reach the network at all.

A connection that dropped, a name that would not resolve, a request that ran out of time. socialchimp already tried again several times before raising this.

This is not the network saying no - it never answered. Unlike most errors here, trying again later is a reasonable thing to do.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}

PlatformError

PlatformError(
    message: str,
    *,
    platform: str,
    status_code: int | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

The network returned an error we do not have a better name for.

The original reply is kept on raw so you can look at what actually happened. If a particular error shows up often, it is worth teaching the platform file to raise something more specific.

Attributes:

Name Type Description
platform

Which network complained.

status_code

HTTP status, when there was one.

raw dict[str, Any]

The network's untouched reply.

Keep the network's own reply alongside our message.

Parameters:

Name Type Description Default
message str

What happened, in our words.

required
platform str

Which network complained.

required
status_code int | None

HTTP status, when there was one.

None
raw dict[str, Any] | None

The network's untouched reply.

None
Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str,
    status_code: int | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Keep the network's own reply alongside our message.

    Args:
        message: What happened, in our words.
        platform: Which network complained.
        status_code: HTTP status, when there was one.
        raw: The network's untouched reply.
    """
    super().__init__(message, platform=platform, raw=raw)
    self.status_code = status_code

Webhooks

SignatureError

SignatureError(
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
)

Bases: SocialChimpError

This request did not come from the network it claims to come from.

Raised when a signature does not match, a shared secret is wrong, a required header is missing, or the request is too old to trust. Treat every one of these the same way: answer 401 and do nothing else. Do not tell the caller which check failed - that only helps whoever is guessing.

Source code in src/socialchimp/errors.py
def __init__(
    self,
    message: str,
    *,
    platform: str | None = None,
    raw: dict[str, Any] | None = None,
) -> None:
    """Record the message, and where it came from.

    Args:
        message: What happened, in plain words.
        platform: Which network complained, if any.
        raw: The network's untouched reply, if there was one.
    """
    super().__init__(message)
    self.platform = platform
    self.raw: dict[str, Any] = raw if raw is not None else {}