Exceptions¶
All library exceptions inherit from MixpanelHeadlessError, enabling callers to catch all library errors with a single except clause.
Explore on DeepWiki
Ask questions about specific exceptions, error recovery patterns, or debugging strategies.
Exception Hierarchy¶
MixpanelHeadlessError
├── ConfigError
│ ├── AccountNotFoundError
│ ├── AccountExistsError
│ ├── AccountInUseError
│ ├── InvalidArgumentError
│ └── ProjectNotFoundError
├── APIError
│ ├── AuthenticationError
│ ├── RateLimitError
│ ├── QueryError
│ └── ServerError
├── OAuthError
│ └── RegionProbeError
│ └── RegionProbeNetworkError
├── WorkspaceScopeError
├── BusinessContextValidationError
├── SessionReplayError (APIError)
├── ReportLinkError
│ ├── ReportLinkParseError
│ ├── UnsupportedReportLinkError
│ ├── ReportLinkNotFoundError
│ ├── ReportLinkScopeMismatchError
│ └── ShortLinkResolutionError
└── HelpLookupError
└── HelpDomainError
Catching Errors¶
import mixpanel_headless as mp
try:
ws = mp.Workspace()
result = ws.segmentation(event="Purchase", from_date="2025-01-01", to_date="2025-01-31")
except mp.AuthenticationError as e:
print(f"Auth failed: {e.message}")
except mp.RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
except mp.OAuthError as e:
print(f"OAuth error [{e.code}]: {e.message}")
except mp.WorkspaceScopeError as e:
print(f"Workspace error [{e.code}]: {e.message}")
except mp.AccountInUseError as e:
print(f"Account '{e.account_name}' referenced by targets: {e.referenced_by}")
except mp.MixpanelHeadlessError as e:
print(f"Error [{e.code}]: {e.message}")
Base Exception¶
mixpanel_headless.MixpanelHeadlessError
¶
MixpanelHeadlessError(
message: str,
code: str = "UNKNOWN_ERROR",
details: dict[str, Any] | None = None,
)
Bases: Exception
Base exception for all mixpanel_headless errors.
All library exceptions inherit from this class, allowing callers to: - Catch all library errors: except MixpanelHeadlessError - Handle specific errors: except AccountNotFoundError - Serialize errors: error.to_dict()
Initialize exception.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
code
|
Machine-readable error code for programmatic handling.
TYPE:
|
details
|
Additional structured data about the error.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
API Exceptions¶
mixpanel_headless.APIError
¶
APIError(
message: str,
*,
status_code: int,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
code: str = "API_ERROR",
)
Bases: MixpanelHeadlessError
Base class for Mixpanel API HTTP errors.
Provides structured access to HTTP request/response context for debugging and automated recovery by AI agents. All API-related exceptions inherit from this class, enabling agents to:
- Understand what went wrong (status code, error message)
- See exactly what was sent (request method, URL, params, body)
- See exactly what came back (response body, headers)
- Modify their approach and retry autonomously
Example
Initialize APIError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
status_code
|
HTTP status code from response.
TYPE:
|
response_body
|
Raw response body (string or parsed dict).
TYPE:
|
request_method
|
HTTP method used (GET, POST).
TYPE:
|
request_url
|
Full request URL.
TYPE:
|
request_params
|
Query parameters sent.
TYPE:
|
request_body
|
Request body sent (for POST requests).
TYPE:
|
code
|
Machine-readable error code.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
response_body
property
¶
Raw response body (string or parsed dict).
mixpanel_headless.AuthenticationError
¶
AuthenticationError(
message: str = "Authentication failed",
*,
status_code: int = 401,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
)
Bases: APIError
Authentication with Mixpanel API failed (HTTP 401).
Raised when credentials are invalid, expired, or lack required permissions. Inherits from APIError to provide full request/response context.
Example
Initialize AuthenticationError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
status_code
|
HTTP status code (default 401).
TYPE:
|
response_body
|
Raw response body.
TYPE:
|
request_method
|
HTTP method used.
TYPE:
|
request_url
|
Full request URL.
TYPE:
|
request_params
|
Query parameters sent.
TYPE:
|
request_body
|
Request body sent (for POST/PATCH requests), so a 401 carries the same context as the other error branches.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.RateLimitError
¶
RateLimitError(
message: str = "Rate limit exceeded",
*,
retry_after: int | None = None,
status_code: int = 429,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
project_id: str | None = None,
)
Bases: APIError
Mixpanel API rate limit exceeded (HTTP 429).
Raised when the API returns a 429 status. The retry_after property indicates when the request can be retried. Inherits from APIError to provide full request context for debugging.
Example
Initialize RateLimitError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
retry_after
|
Seconds until retry is allowed (from Retry-After header).
TYPE:
|
status_code
|
HTTP status code (default 429).
TYPE:
|
response_body
|
Raw response body.
TYPE:
|
request_method
|
HTTP method used.
TYPE:
|
request_url
|
Full request URL.
TYPE:
|
request_params
|
Query parameters sent.
TYPE:
|
project_id
|
Mixpanel project id active when the limit was hit, used
to prefill the rate-limit-increase request form.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
project_id
property
¶
Mixpanel project id active when the rate limit was hit, if known.
rate_limit_form_url
property
¶
URL to request a rate-limit increase.
Returns the project-prefilled Google Form URL when the project id is known (so the lead is attributed to a project), otherwise the short form link. Handy for surfacing in scripts or notebooks that catch this error.
| RETURNS | DESCRIPTION |
|---|---|
str
|
The rate-limit-increase request form URL. |
mixpanel_headless.QueryError
¶
QueryError(
message: str = "Query execution failed",
*,
status_code: int = 400,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
)
Bases: APIError
Query execution failed (HTTP 400 or query-specific error).
Raised when an API query fails due to invalid parameters, syntax errors, or other query-specific issues. Inherits from APIError to provide full request/response context for debugging.
Example
Initialize QueryError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
status_code
|
HTTP status code (default 400).
TYPE:
|
response_body
|
Raw response body with error details.
TYPE:
|
request_method
|
HTTP method used.
TYPE:
|
request_url
|
Full request URL.
TYPE:
|
request_params
|
Query parameters sent.
TYPE:
|
request_body
|
Request body sent (for POST).
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ServerError
¶
ServerError(
message: str = "Server error",
*,
status_code: int = 500,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
)
Bases: APIError
Mixpanel server error (HTTP 5xx).
Raised when the Mixpanel API returns a server error. These are typically transient issues that may succeed on retry. The response_body property contains the full error details from Mixpanel, which often include actionable information (e.g., "unit and interval both specified").
Example
Initialize ServerError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
status_code
|
HTTP status code (5xx).
TYPE:
|
response_body
|
Raw response body with error details.
TYPE:
|
request_method
|
HTTP method used.
TYPE:
|
request_url
|
Full request URL.
TYPE:
|
request_params
|
Query parameters sent.
TYPE:
|
request_body
|
Request body sent (for POST).
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
Configuration Exceptions¶
mixpanel_headless.ConfigError
¶
Bases: MixpanelHeadlessError
Base for configuration-related errors.
Raised when there's a problem with configuration files, environment variables, or credential resolution.
Initialize ConfigError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
details
|
Additional structured data.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.AccountNotFoundError
¶
Bases: ConfigError
Named account does not exist in configuration.
Raised when attempting to access an account that hasn't been configured. The available_accounts property lists valid account names to help users.
Initialize AccountNotFoundError.
| PARAMETER | DESCRIPTION |
|---|---|
account_name
|
The requested account name that wasn't found.
TYPE:
|
available_accounts
|
List of valid account names for suggestions.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.AccountExistsError
¶
Bases: ConfigError
Account name already exists in configuration.
Raised when attempting to add an account with a name that's already in use.
Initialize AccountExistsError.
| PARAMETER | DESCRIPTION |
|---|---|
account_name
|
The conflicting account name.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.AccountInUseError
¶
Bases: ConfigError
Account is referenced by one or more targets and cannot be removed.
Raised by mp.accounts.remove(name) when the account is referenced by
one or more [targets.NAME] blocks and the caller did not pass
force=True. The list of dependent target names is available in
referenced_by so callers can show a helpful error message or pass
force=True to delete the account and orphan the targets.
Initialize AccountInUseError.
| PARAMETER | DESCRIPTION |
|---|---|
account_name
|
The account that callers tried to remove.
TYPE:
|
referenced_by
|
Names of targets that reference the account.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ProjectNotFoundError
¶
Bases: ConfigError
Raised when a specified project is not accessible.
Includes the requested project ID and optionally a list of accessible project IDs to help the user correct their selection.
Example
try:
projects = ws.projects()
match = [p for p in projects if p.id == target_id]
if not match:
raise ProjectNotFoundError(
target_id,
available_projects=[p.id for p in projects],
)
except ProjectNotFoundError as e:
print(f"Project '{e.project_id}' not found.")
if e.available_projects:
print(f"Available: {', '.join(e.available_projects)}")
Initialize ProjectNotFoundError.
| PARAMETER | DESCRIPTION |
|---|---|
project_id
|
The requested project ID that wasn't found.
TYPE:
|
available_projects
|
List of accessible project IDs for suggestions.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
InvalidArgumentError¶
Raised by accounts.login_unified (and the CLI's mp login) when a public-API call combines mutually incompatible arguments. Subclass of ConfigError. The CLI maps this to exit code 3 (INVALID_ARGS) instead of the generic 1.
violation |
Raised When |
|---|---|
mutually_exclusive |
--service-account + --token-env (or equivalent kwargs) |
no_browser_misuse |
--no-browser against a non-browser auth type |
secret_stdin_misuse |
--secret-stdin against a non-SA auth type |
The details dict carries violation and (when detection ran) detected_auth_type. Pattern-match by class so non-CLI callers (Cowork's auth_manager.py, JSON consumers) can dispatch without parsing the human message.
mixpanel_headless.InvalidArgumentError
¶
InvalidArgumentError(
message: str,
*,
violation: Literal[
"mutually_exclusive", "no_browser_misuse", "secret_stdin_misuse"
],
detected_auth_type: str | None = None,
)
Bases: ConfigError
Raised when a public API call combines mutually incompatible arguments.
Carries a violation discriminator and the resolved
detected_auth_type so non-CLI callers (Cowork's auth_manager.py,
JSON consumers) can dispatch programmatically without parsing the
human message. The CLI handle_errors decorator maps this subclass
to ExitCode.INVALID_ARGS (3) instead of the generic
GENERAL_ERROR (1) that ConfigError would otherwise produce.
Used by accounts.login_unified for the three documented
flag-combination rejections (043 contract, cli-commands.md §5):
--service-account + --token-env, --no-browser against a
non-browser auth type, and --secret-stdin against a non-SA
auth type.
Example
Initialize InvalidArgumentError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
violation
|
Discriminator for the kind of misuse. One of
TYPE:
|
detected_auth_type
|
The auth type the orchestrator resolved
from the supplied flags / env.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
OAuth Exceptions¶
Raised during OAuth 2.0 PKCE authentication flows and the mp login region probe.
| Error Code | Raised When |
|---|---|
OAUTH_TOKEN_ERROR |
Token exchange fails |
OAUTH_REFRESH_ERROR |
Token refresh fails (transient) |
OAUTH_REFRESH_REVOKED |
Refresh token rejected by IdP as invalid_grant (re-run mp login --name NAME) |
OAUTH_REGISTRATION_ERROR |
Dynamic client registration fails |
OAUTH_TIMEOUT |
Callback server times out waiting for authorization |
OAUTH_PORT_ERROR |
Cannot bind to a local port for the callback server |
OAUTH_BROWSER_ERROR |
Cannot open the authorization URL in the browser |
OAUTH_REGION_PROBE_FAILED |
mp login probed every region and none accepted the credential — see RegionProbeError below |
OAUTH_NETWORK_UNREACHABLE |
Every region probe failed at the network layer (DNS / TLS / connect refused) — see RegionProbeNetworkError below |
mixpanel_headless.OAuthError
¶
Bases: MixpanelHeadlessError
OAuth authentication flow error.
Raised for failures during the OAuth 2.0 PKCE flow, including token exchange, token refresh, client registration, callback timeout, port unavailability, and browser launch failures.
Error codes: - OAUTH_TOKEN_ERROR: Token exchange or validation failed - OAUTH_REFRESH_ERROR: Token refresh failed - OAUTH_REGISTRATION_ERROR: Dynamic Client Registration failed - OAUTH_TIMEOUT: Callback server timed out waiting for authorization - OAUTH_PORT_ERROR: All callback ports are occupied - OAUTH_BROWSER_ERROR: Could not open browser for authorization
Example
Initialize OAuthError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
code
|
Machine-readable error code. One of: OAUTH_TOKEN_ERROR, OAUTH_REFRESH_ERROR, OAUTH_REGISTRATION_ERROR, OAUTH_TIMEOUT, OAUTH_PORT_ERROR, OAUTH_BROWSER_ERROR.
TYPE:
|
details
|
Additional structured data about the error.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
RegionProbeError¶
Raised by mp login (and accounts.login_unified) when the us → eu → in region probe fails for every region. Subclass of OAuthError. The attempts attribute carries the full (region, status_code, error_body) list; status 0 indicates a network-layer failure (DNS / TLS / connect refused) — those cases raise RegionProbeNetworkError (subclass) so the CLI can render a different remediation hint.
import mixpanel_headless as mp
try:
mp.accounts.login_unified()
except mp.RegionProbeNetworkError as exc:
print("Could not reach any Mixpanel region. Check connectivity.")
for region, status, body in exc.attempts:
print(f" {region}: {body}")
except mp.RegionProbeError as exc:
print("Credential not valid in any region.")
for region, status, body in exc.attempts:
print(f" {region}: {status} {body}")
mixpanel_headless.RegionProbeError
¶
RegionProbeError(
message: str,
*,
attempts: list[tuple[Region, int, str]],
code: str = "OAUTH_REGION_PROBE_FAILED",
)
Bases: OAuthError
Raised when no region accepts the credential during region probing.
The region probe walks a configured order (default us → eu →
in) against /api/app/me, returning the first 200. When every
probe attempt fails, this exception is raised carrying the full
attempt list for diagnostic and telemetry use.
A status code of 0 indicates the request never reached the server
(network error); the third tuple element carries the failure detail
(HTTP response text or the network error reason).
See :class:RegionProbeNetworkError for the all-network-error
subclass — the probe distinguishes "credential rejected" from
"could not reach any region" so the CLI can render different
remediation hints.
Example
Initialize RegionProbeError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
attempts
|
Ordered list of
TYPE:
|
code
|
Machine-readable error code. Defaults to
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
attempts
property
¶
Ordered list of (region, status_code, error_body) tuples.
to_dict
¶
Serialize the exception to a JSON-friendly dict.
Includes attempts at the top level so consumers can inspect
the per-region probe outcomes without unpacking details.
| RETURNS | DESCRIPTION |
|---|---|
dict[str, Any]
|
Dictionary with keys |
dict[str, Any]
|
|
dict[str, Any]
|
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.RegionProbeNetworkError
¶
Bases: RegionProbeError
Raised when every region probe attempt failed at the network layer.
Subclass of :class:RegionProbeError used when ALL recorded
attempts have status_code == 0 — i.e. the credential was never
actually evaluated because no region was reachable (DNS failure,
TLS rejection, captive portal, no internet). The CLI catches this
before the generic RegionProbeError so it can render "could
not reach any Mixpanel region" instead of "credential not valid",
which would mislead a user who is actually offline.
Carries the same attempts shape as the parent so existing
consumers can render the per-region detail without changes.
Initialize RegionProbeNetworkError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
attempts
|
Ordered list of
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
Workspace / Organization Scope Exceptions¶
Raised when an auth-axis identifier (workspace or organization) cannot be resolved during App API requests.
| Error Code | Raised When |
|---|---|
NO_WORKSPACES |
No workspaces found for the project |
AMBIGUOUS_WORKSPACE |
Multiple workspaces found and none is marked as default |
WORKSPACE_NOT_FOUND |
Specified workspace ID does not exist |
ORGANIZATION_AMBIGUOUS |
An org-scoped business-context call could not auto-resolve the organization (active project absent from /me AND >1 accessible organization). details carries project_id and available_organizations. Pass organization_id=N explicitly to bypass auto-resolution. |
mixpanel_headless.WorkspaceScopeError
¶
WorkspaceScopeError(
message: str,
code: str = "NO_WORKSPACES",
details: dict[str, Any] | None = None,
)
Bases: MixpanelHeadlessError
Scope resolution error (workspace or organization).
Raised when an auth-axis identifier cannot be resolved during App
API requests. Originally introduced for workspace resolution; also
raised when the organization ID for an org-scoped business-context
call cannot be auto-derived from the cached /me response.
Error codes:
- NO_WORKSPACES: Project has no accessible workspaces
- AMBIGUOUS_WORKSPACE: Multiple workspaces, none default; must specify --workspace-id
- WORKSPACE_NOT_FOUND: Explicit workspace ID doesn't match any workspace
- ORGANIZATION_AMBIGUOUS: Cannot auto-resolve the organization for an
org-scoped call (active project absent from /me AND >1 accessible
organization). The details dict carries project_id and
available_organizations. Pass organization_id=N explicitly
to bypass auto-resolution.
Example
Initialize WorkspaceScopeError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
code
|
Machine-readable error code. One of: NO_WORKSPACES, AMBIGUOUS_WORKSPACE, WORKSPACE_NOT_FOUND, ORGANIZATION_AMBIGUOUS.
TYPE:
|
details
|
Additional structured data about the error.
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
Business Context Exceptions¶
Raised by Workspace.set_business_context() when content exceeds the 50,000-character cap. The check runs before the HTTP call, so callers fail fast and don't waste a round-trip; the server enforces the same limit and would otherwise return QueryError (HTTP 400). See the Business Context guide for usage.
| Error Code | Raised When |
|---|---|
BUSINESS_CONTEXT_TOO_LONG |
len(content) > BUSINESS_CONTEXT_MAX_CHARS (50,000) |
The details dict carries length (the actual content length) and max (the configured limit) for programmatic recovery.
mixpanel_headless.BusinessContextValidationError
¶
Bases: MixpanelHeadlessError
Business context content failed client-side validation.
Raised by Workspace.set_business_context() when the supplied
content exceeds BUSINESS_CONTEXT_MAX_CHARS (50,000 characters).
The check runs before the HTTP call so callers can fail fast and
avoid a wasted round-trip — the server enforces the same limit
server-side and would otherwise return QueryError (HTTP 400).
The details dict carries length (the actual content length)
and max (the configured limit) for programmatic recovery.
Example
Initialize BusinessContextValidationError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message.
TYPE:
|
details
|
Additional structured data — typically
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
Session Replay Exceptions¶
Raised by the session-replay surface (fetch_replay(), sign_replay(), stream_replay()). SessionReplayError is the base — catch it to handle any replay failure. See the Session Replay guide.
| Exception | Raised When |
|---|---|
SessionReplayAccessError |
The project has the SESSION_RECORDING_SENSITIVE_DATA flag set and the caller lacks the sensitive_data_replay permission (HTTP 403). details carries project_id, flag, and permission_required. |
SignedURLExpiredError |
A signed CDN URL expired mid-fetch (~5-minute TTL) and re-signing was disabled or also failed. |
ReplayNotFoundError |
The replay's first CDN file returned 404 — it aged out of its retention window, was never recorded, or was deleted. |
mixpanel_headless.SessionReplayError
¶
SessionReplayError(
message: str,
*,
details: dict[str, Any] | None = None,
status_code: int | None = None,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
code: str | None = None,
)
Bases: APIError
Base class for session-replay-specific failures.
Subclasses cover the three replay-specific failure modes:
:class:SessionReplayAccessError (sensitive-data permission denied),
:class:SignedURLExpiredError (5-minute signed-URL TTL elapsed), and
:class:ReplayNotFoundError (CDN walker found no bytes for the
replay). All carry the standard :class:APIError HTTP context
(status_code, response_body, request_url, etc.) plus a
replay-specific details dict that the subclass merges in on top
(replay_id, project_id, flag, retention_days, …).
Catch this base class to handle any replay failure uniformly:
Example
Because :class:SessionReplayError is an :class:APIError, existing
except APIError: handlers — including the CLI handle_errors
decorator that maps HTTP failures to exit codes — continue to catch
these without modification.
Initialize SessionReplayError.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message; see error-messages.md for the catalog of stable wording per subclass.
TYPE:
|
details
|
Replay-specific structured context (
TYPE:
|
status_code
|
HTTP status that triggered the error. Defaults
to the subclass's
TYPE:
|
response_body
|
Raw response body for debugging.
TYPE:
|
request_method
|
HTTP method (GET, POST, …).
TYPE:
|
request_url
|
Full request URL.
TYPE:
|
request_params
|
Query parameters sent on the failing request.
TYPE:
|
request_body
|
Request body sent on the failing request.
TYPE:
|
code
|
Machine-readable error code. Defaults to the subclass's
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.SessionReplayAccessError
¶
SessionReplayAccessError(
message: str,
*,
details: dict[str, Any] | None = None,
status_code: int | None = None,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
code: str | None = None,
)
Bases: SessionReplayError
Project has SESSION_RECORDING_SENSITIVE_DATA enabled and caller lacks access.
Raised when the bulk-sign endpoint returns 403 with a body that
mentions the SESSION_RECORDING_SENSITIVE_DATA project flag. The
project owner can grant the sensitive_data_replay permission to
unblock the caller; a service account with that permission works too.
Details
project_id (int): The project that gated the call.
flag (str): Always "SESSION_RECORDING_SENSITIVE_DATA".
permission_required (str): Always "sensitive_data_replay".
See error-messages.md §1 for the canonical message wording.
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.SignedURLExpiredError
¶
SignedURLExpiredError(
message: str,
*,
details: dict[str, Any] | None = None,
status_code: int | None = None,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
code: str | None = None,
)
Bases: SessionReplayError
Signed CDN URL passed to a fetch has expired (5-minute TTL).
Raised when a CDN fetch returns 403 with an expiration body AND the
caller opted out of automatic re-signing (stream_replay with
re_sign_on_expiry=False). Re-sign via :meth:Workspace.sign_replay
and retry, or pass re_sign_on_expiry=True (the default) to let the
library re-sign transparently.
Details
replay_id (str): The replay whose URL expired.
signed_at (float): Unix seconds when the original URL was signed.
expired_at (float): Unix seconds when the URL expired
(typically signed_at + 300).
See error-messages.md §2 for the canonical message wording.
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ReplayNotFoundError
¶
ReplayNotFoundError(
message: str,
*,
details: dict[str, Any] | None = None,
status_code: int | None = None,
response_body: str | dict[str, Any] | None = None,
request_method: str | None = None,
request_url: str | None = None,
request_params: dict[str, Any] | None = None,
request_body: dict[str, Any] | None = None,
code: str | None = None,
)
Bases: SessionReplayError
No CDN bytes found for a requested replay.
Raised when the CDN walker hits a 404 on the very first file
(0000-N.json). The replay either aged out of its retention
window, was never recorded, or has been deleted. Mid-walk 404s are
treated as the end-of-replay sentinel and do NOT raise.
Details
replay_id (str): The replay that returned no bytes. retention_days (int): The retention window that was assumed (1, 7, 30, or 90). cdn_url_prefix (str): The CDN prefix that was walked.
See error-messages.md §3 for the canonical message wording.
Source code in src/mixpanel_headless/exceptions.py
Report Link Exceptions¶
Raised by the report-link surface (create_report_link(), resolve_report_link(), query_report_link(), saved_report_link()). ReportLinkError is the base — catch it to handle any link failure. Every instance carries the parsed link parts (kind, region, project_id, workspace_id, slug, bookmark_id, short_code, as available) plus a hint in details. See the Report Links guide.
| Exception | Codes | Raised When |
|---|---|---|
ReportLinkParseError |
REPORT_LINK_UNPARSEABLE, REPORT_LINK_NOT_MIXPANEL_HOST, REPORT_LINK_UNRECOGNIZED_PATH, REPORT_LINK_UNRECOGNIZED_HASH, REPORT_LINK_EMPTY_HASH |
The string is not a recognizable Mixpanel report link. The parser is total: this is the only error it raises. |
UnsupportedReportLinkError |
UNSUPPORTED_LEGACY_HASH, UNSUPPORTED_DASHBOARD_LINK, UNSUPPORTED_REPORT_TYPE |
A legacy ~(...) hash, a board link, or a launch-analysis report passed to query_report_link. |
ReportLinkNotFoundError |
REPORT_LINK_SLUG_NOT_FOUND, REPORT_LINK_BOOKMARK_NOT_FOUND, SHORT_LINK_NOT_FOUND |
The slug, saved report, or shortlink does not exist in the active project and region. CLI exit 4. |
ReportLinkScopeMismatchError |
REPORT_LINK_PROJECT_MISMATCH, REPORT_LINK_REGION_MISMATCH, REPORT_LINK_WORKSPACE_MISMATCH |
The link names another project or region, or a workspace other than the pinned session workspace. The region check runs before any HTTP call; the project and workspace checks run before the record fetch (for a shortlink, after the one redirect GET). The message names both values; details["hint"] names the ws.use(...) call and the mp --account / mp --project / mp --workspace flag that fixes it. |
ShortLinkResolutionError |
SHORT_LINK_NO_LOCATION, SHORT_LINK_UNEXPECTED_RESPONSE, SHORT_LINK_CHAIN |
The shortlink server answered in a shape headless cannot extract a target from, or the target is another shortlink. CLI exit 1. |
Builder and input guards raise ParamValidationError, not a ReportLinkError, with RL1_UNKNOWN_REPORT_TYPE, RL2_INVALID_SLUG, RL3_UNKNOWN_REGION, RL4_REPORT_TYPE_CONFLICT, RL5_RESOLVED_REPORT_INCONSISTENT (a hand-built ResolvedReport whose source and id fields disagree), or RL6_INVALID_ID (a zero or negative project, workspace, or bookmark id passed to a URL builder). A shortlink that redirects to the login page raises the existing AuthenticationError; a 403 on the shortlink raises QueryError.
mixpanel_headless.ReportLinkError
¶
Bases: MixpanelHeadlessError
Base class for report-link failures (045-report-links).
Report links are Mixpanel web URLs that open a report in the browser.
Most failures in this family are local — a link that does not parse, a
link that points at another project or region, or a link kind that
headless cannot resolve — so the base is :class:MixpanelHeadlessError
rather than :class:APIError. The HTTP-shaped failures,
:class:ReportLinkNotFoundError and :class:ShortLinkResolutionError,
carry the parsed link fields in details instead of HTTP context.
Subclasses: :class:ReportLinkParseError,
:class:UnsupportedReportLinkError, :class:ReportLinkNotFoundError,
:class:ReportLinkScopeMismatchError, :class:ShortLinkResolutionError.
Not in this family: the pure URL builders and create_report_link
input guards raise :class:ParamValidationError with the codes
RL1_UNKNOWN_REPORT_TYPE, RL2_INVALID_SLUG, RL3_UNKNOWN_REGION,
RL4_REPORT_TYPE_CONFLICT, RL5_RESOLVED_REPORT_INCONSISTENT, and
RL6_INVALID_ID. A try/except ReportLinkError does not catch them. Every failure in this
family carries a hint in details.
Example
Initialize a report-link error.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable error message; see
TYPE:
|
code
|
Machine-readable error code. Defaults to the subclass's
TYPE:
|
details
|
Parsed link fields that are available (
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ReportLinkParseError
¶
ReportLinkParseError(
message: str,
*,
code: str | None = None,
details: dict[str, Any] | None = None,
)
Bases: ReportLinkError
The input string is not a recognizable Mixpanel report link.
Codes: REPORT_LINK_UNPARSEABLE (default),
REPORT_LINK_NOT_MIXPANEL_HOST, REPORT_LINK_UNRECOGNIZED_PATH,
REPORT_LINK_UNRECOGNIZED_HASH, REPORT_LINK_EMPTY_HASH. The parser
is total: this is the only exception it raises for any input string.
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.UnsupportedReportLinkError
¶
UnsupportedReportLinkError(
message: str,
*,
code: str | None = None,
details: dict[str, Any] | None = None,
)
Bases: ReportLinkError
The link was recognized but headless cannot resolve or run it.
Codes: UNSUPPORTED_REPORT_LINK (default), UNSUPPORTED_LEGACY_HASH
(a ~(...) JSURL hash), UNSUPPORTED_DASHBOARD_LINK (a board, not a
single report), UNSUPPORTED_REPORT_TYPE (for example
launch-analysis passed to query_report_link).
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ReportLinkNotFoundError
¶
ReportLinkNotFoundError(
message: str,
*,
code: str | None = None,
details: dict[str, Any] | None = None,
)
Bases: ReportLinkError
The slug, saved report, or shortlink does not exist in scope.
Codes: REPORT_LINK_NOT_FOUND (default), REPORT_LINK_SLUG_NOT_FOUND,
REPORT_LINK_BOOKMARK_NOT_FOUND, SHORT_LINK_NOT_FOUND. A slug is
readable only in the project and region that created it, so a 404 on a
slug often means the caller is on the wrong project.
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ReportLinkScopeMismatchError
¶
ReportLinkScopeMismatchError(
message: str,
*,
code: str | None = None,
details: dict[str, Any] | None = None,
)
Bases: ReportLinkError
The link names a project or region other than the active session.
Codes: REPORT_LINK_SCOPE_MISMATCH (default),
REPORT_LINK_PROJECT_MISMATCH, REPORT_LINK_REGION_MISMATCH,
REPORT_LINK_WORKSPACE_MISMATCH (only when the session pins a
workspace and the link names a different one). The region check runs
before any HTTP call. The project and workspace checks run before the
record fetch; for a shortlink that is after the one redirect GET, because
the target is not known before it. The message names both values, and
details["hint"] names the ws.use(...) call and the mp --account,
mp --project, or mp --workspace flag that fixes it.
Source code in src/mixpanel_headless/exceptions.py
mixpanel_headless.ShortLinkResolutionError
¶
ShortLinkResolutionError(
message: str,
*,
code: str | None = None,
details: dict[str, Any] | None = None,
)
Bases: ReportLinkError
A /s/{code} shortlink could not be expanded to a full report URL.
Codes: SHORT_LINK_RESOLUTION_ERROR (default), SHORT_LINK_NO_LOCATION
(3xx without Location), SHORT_LINK_UNEXPECTED_RESPONSE (200 body
without the window.location.href script), SHORT_LINK_CHAIN (the
target is another shortlink; headless follows one redirect only).
Source code in src/mixpanel_headless/exceptions.py
Help Lookup Exceptions¶
HelpLookupError is raised by the built-in help surface (mixpanel_headless.reference.describe(), and search() for an empty term) when a query names no export, no Workspace member, and no parameter. The lookup is fully offline, so this is never an HTTP failure; the base is MixpanelHeadlessError, not APIError. mixpanel_headless.help() catches it and prints the suggestions and the first search hits instead of raising. The CLI prints the same text on stdout and exits 4. See the Built-in Help guide.
| Attribute | Content |
|---|---|
query |
The query string as the caller gave it. |
suggestions |
Close names, most similar first; () when none. |
hits |
SearchHit records for the same term; () when none. Also present in details (and to_dict()) as dicts. |
import mixpanel_headless as mp
from mixpanel_headless import reference as ref
try:
entry = ref.describe("Filtr")
except mp.HelpLookupError as exc:
print(exc.query, exc.suggestions)
mixpanel_headless.HelpLookupError
¶
Bases: MixpanelHeadlessError
A mixpanel_headless.help() / reference.describe() query matched nothing.
Raised by :func:mixpanel_headless.reference.describe (and re-raised by
:func:mixpanel_headless.reference.search for an empty term) when the
query names no export, no Workspace member, and no parameter. The
lookup is fully offline, so this is never an HTTP failure and the base is
:class:MixpanelHeadlessError, not :class:APIError. The CLI maps it to
ExitCode.NOT_FOUND (4).
The instance carries the structured recovery data the plain-text
help() wrapper prints: close-name suggestions (difflib) and the
first search hits for the same term.
| ATTRIBUTE | DESCRIPTION |
|---|---|
query |
The query string as the caller gave it.
TYPE:
|
suggestions |
Close names in
TYPE:
|
hits |
Search hits (
TYPE:
|
Example
Initialize a help lookup miss.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
The query string that matched nothing.
TYPE:
|
suggestions
|
Close names to offer, most similar first. Stored as
a tuple. Rendered as
TYPE:
|
hits
|
Search hits for the same term. Stored as a tuple and kept
out of the message; the
TYPE:
|
Source code in src/mixpanel_headless/exceptions.py
HelpDomainError subclasses HelpLookupError and is raised by describe() when the domain= filter is rejected: the domain matches no registered Workspace domain title, matches several titles (an ambiguous prefix), or is given with a query other than Workspace. The query itself resolved, so help() re-raises it instead of printing a miss, and the CLI prints the message plus one Domains: line on stderr and exits 3.
| Attribute | Content |
|---|---|
query |
The help query text ("Workspace", "Filter"), never the domain. |
domain |
The domain= value as the caller gave it. |
domains |
Every registered title for an unknown domain, the candidate titles for an ambiguous prefix, () for a non-Workspace query. Mirrored into suggestions. |
reason |
"unknown", "ambiguous", or "not_workspace" (the HelpDomainReason literal). |
import mixpanel_headless as mp
from mixpanel_headless import reference as ref
try:
ref.describe("Workspace", domain="s")
except mp.HelpDomainError as exc:
print(exc.reason, exc.domains)
# ambiguous ('session and switching', 'streaming', 'schema registry', 'schema enforcement', 'session replay')
mixpanel_headless.HelpDomainError
¶
HelpDomainError(
query: str,
*,
domain: str,
domains: Sequence[str] = (),
reason: HelpDomainReason = "unknown",
)
Bases: HelpLookupError
The domain= filter of a help query was rejected.
Raised by :func:mixpanel_headless.reference.describe when domain
matches no registered Workspace domain title, matches several titles
(an ambiguous prefix), or is given with a query other than the
Workspace listing. The query itself resolved fine, so this is not a
lookup miss: :func:mixpanel_headless.reference.help re-raises it
instead of printing suggestions, and the CLI maps it to
ExitCode.INVALID_ARGS (3) instead of NOT_FOUND (4).
It subclasses :class:HelpLookupError so an except HelpLookupError
still catches it; suggestions mirrors domains and hits is
always empty.
| ATTRIBUTE | DESCRIPTION |
|---|---|
query |
The help query text (
|
domain |
The
TYPE:
|
domains |
Every registered title for an unknown domain, the candidate
titles for an ambiguous prefix,
TYPE:
|
reason |
TYPE:
|
Example
Initialize a rejected domain filter.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
The help query text the filter was applied to.
TYPE:
|
domain
|
The rejected
TYPE:
|
domains
|
Titles to offer: all of them for
TYPE:
|
reason
|
Which check failed; picks the message.
TYPE:
|