2025-06-17 12:58:00 +05:30
|
|
|
"""
|
|
|
|
|
Composio exceptions.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import difflib
|
|
|
|
|
import typing as t
|
|
|
|
|
|
|
|
|
|
ENV_COMPOSIO_API_KEY = "COMPOSIO_API_KEY"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ComposioError(Exception):
|
|
|
|
|
"""Base composio SDK error."""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
message: str,
|
|
|
|
|
*args: t.Any,
|
|
|
|
|
delegate: bool = False,
|
|
|
|
|
) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Initialize Composio SDK error.
|
|
|
|
|
|
|
|
|
|
:param message: Error message
|
|
|
|
|
:param delegate: Whether to delegate the error message to the log
|
|
|
|
|
collection server or not
|
|
|
|
|
"""
|
|
|
|
|
super().__init__(message, *args)
|
|
|
|
|
self.message = message
|
|
|
|
|
self.delegate = delegate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NotFoundError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class HTTPError(ComposioError):
|
|
|
|
|
"""
|
|
|
|
|
Exception class for HTTP API errors.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
message: str,
|
|
|
|
|
status_code: int,
|
|
|
|
|
*args: t.Any,
|
|
|
|
|
delegate: bool = False,
|
|
|
|
|
) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Initialize HTTPError class.
|
|
|
|
|
|
|
|
|
|
:param message: Content from the API response
|
|
|
|
|
:param status_code: HTTP response status code
|
|
|
|
|
:param delegate: Whether to delegate the error message to the log
|
|
|
|
|
collection server or not
|
|
|
|
|
"""
|
|
|
|
|
super().__init__(message, *args, delegate=delegate)
|
|
|
|
|
self.status_code = status_code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ComposioClientError(ComposioError):
|
|
|
|
|
"""
|
|
|
|
|
Exception class for Composio client errors.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SDKError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProcessorError(SDKError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EnumError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ValidationError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
fix(py): resolve $ref/$defs so file flags behind a reference aren't dropped (#3653)
## Problem
Tools whose parameter schemas express their file fields through a
`$ref`/`$defs` indirection lose auto file handling. With
`dangerously_allow_auto_upload_download_files=True`, a
`file_downloadable` output behind a `$ref` is never downloaded (the raw
`{name, mimetype, s3url}` object is passed through), and a
`file_uploadable` input behind a `$ref` is never staged — silently, with
no error.
`GMAIL_GET_ATTACHMENT` is the canonical shape — the flag sits two `$ref`
hops deep:
```
data → $ref → #/$defs/GetAttachmentResponse → file → $ref → #/$defs/FileDownloadable (file_downloadable: true)
```
**Root cause:** the hand-rolled walkers in
`composio/core/models/_files.py` (`_has_file_property`,
`_substitute_file_upload_value`, `_substitute_file_download_value`, …)
recurse through `properties`/`anyOf`/`oneOf`/`allOf`/`items` but **never
dereference `$ref`**, so a flagged node reachable only through a
reference is invisible to them.
Fixes https://github.com/ComposioHQ/composio/issues/3506
## Approach
Rather than teach each walker to dereference — which means threading a
root schema through ~10 methods, re-deriving `$ref` handling in each,
and risking unbounded recursion on cyclic schemas — this introduces a
single **`dereference_json_schema`** utility and inlines references
**once at the `FileHelper` boundary** (`process_file_uploadable_schema`,
`substitute_file_uploads`, `substitute_file_downloads`). The walkers
stay reference-agnostic.
This mirrors the TypeScript SDK's `dereferenceJsonSchema` (the
counterpart fix in #3566 for the TS twin of this bug, #3307) so both
SDKs share one behavioral contract. Resolving once at the boundary also
gives every walker `$ref` support for free — including keywords they
never special-cased (`additionalProperties`, `patternProperties`,
`prefixItems`, `not`), because the resolver walks containers
reflectively.
## What's in the utility (`composio/utils/json_schema.py`)
Faithful port of the TS guards:
- **Cycle safety** — breaks both `$ref` cycles and live-object identity
cycles with a permissive `{type: object, additionalProperties: true}`
sentinel. (A per-node lazy resolver without threaded cycle tracking
infinite-loops on a self-referential schema; there's a regression test
for exactly this.)
- **Depth caps** — `MAX_REF_CHAIN_DEPTH=100` / `MAX_NODE_DEPTH=512`
raise a typed `JSONSchemaRefResolutionError` instead of exhausting the
interpreter (with a `RecursionError` backstop converted to the same
typed error).
- **Sibling-keyword merge** — Draft 2020-12 semantics (siblings win on
collision), so a `description`/`default` next to a `$ref` survives.
- **External-ref passthrough** — `http(s)://` refs are left untouched
and logged once for audit.
- **`sentinel` mode** — a dangling `$ref` (an API schema that emits
`$ref` with no `$defs` block,
https://github.com/ComposioHQ/composio/issues/3307) degrades to the
permissive sentinel + an LLM-visible hint, instead of aborting the tool
call. The `FileHelper` uses this mode for API-sourced schemas.
- **Non-mutating** — returns a new schema; `$defs`/`definitions` are
stripped from the inlined root.
## Tests
- `python/tests/test_json_schema.py` — 30 cases mirroring the TS
`jsonSchema.test.ts` contract (chains, reflective container walk, legacy
`definitions`, sibling merge, cycles, depth caps, pointer-escape
decoding, array-index pointers, full `sentinel`-mode suite).
- `python/tests/test_files.py` — end-to-end regressions through the
public methods: download/upload behind `$ref`/`$defs` (the #3506 repro),
the LLM-facing input transform, graceful degradation of a dangling
`$ref`, and a **self-referential schema that must not recurse
infinitely**.
- `nox -s chk` (ruff + mypy) green; `nox -s tst` for the file/execution
suites green.
## Notes
Supersedes #3545 (third-party PR that fixed the same bug by threading
`root_schema` through each walker). That diagnosis was correct; this
takes the centralized route consistent with the TS SDK and adds the
cycle/depth guards. No changeset — Python-package change.
2026-06-25 00:53:50 +04:00
|
|
|
class JSONSchemaRefResolutionError(ValidationError):
|
|
|
|
|
"""Raised when an internal JSON Schema ``$ref`` cannot be inlined.
|
|
|
|
|
|
|
|
|
|
Covers malformed pointers, missing ``$defs``/``definitions`` targets
|
|
|
|
|
(strict mode only), and ``$ref`` chains or node nesting that exceed the
|
|
|
|
|
safety caps in :func:`composio.utils.json_schema.dereference_json_schema`.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
message: str,
|
|
|
|
|
*args: t.Any,
|
|
|
|
|
meta: t.Optional[t.Dict[str, t.Any]] = None,
|
|
|
|
|
delegate: bool = False,
|
|
|
|
|
) -> None:
|
|
|
|
|
super().__init__(message, *args, delegate=delegate)
|
|
|
|
|
self.meta = meta or {}
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class ToolkitError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EntityIDError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PluginError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidParams(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FileError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ComposioSDKTimeoutError(ComposioError, TimeoutError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SDKFileNotFoundError(ComposioError, FileNotFoundError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LockFileError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VersionError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidLockFile(LockFileError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidVersionString(EnumError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VersionSelectionError(LockFileError, VersionError):
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
action: str,
|
|
|
|
|
requested: str,
|
|
|
|
|
locked: str,
|
|
|
|
|
delegate: bool = False,
|
|
|
|
|
) -> None:
|
|
|
|
|
self.action = action
|
|
|
|
|
self.requested = requested
|
|
|
|
|
self.locked = locked
|
|
|
|
|
super().__init__(
|
|
|
|
|
message=(
|
|
|
|
|
f"Error selecting version for action: {action!r}, "
|
|
|
|
|
f"requested: {requested!r}, locked: {locked!r}"
|
|
|
|
|
),
|
|
|
|
|
delegate=delegate,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidEnum(EnumError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EnumStringNotFound(EnumError):
|
|
|
|
|
"""Raise when user provides invalid enum string."""
|
|
|
|
|
|
|
|
|
|
def __init__(self, value: str, enum: str, possible_values: t.List[str]) -> None:
|
|
|
|
|
error_message = f"Invalid value `{value}` for enum class `{enum}`"
|
|
|
|
|
matches = difflib.get_close_matches(value, possible_values, n=1)
|
|
|
|
|
if matches:
|
|
|
|
|
(match,) = matches
|
|
|
|
|
error_message += f". Did you mean {match!r}?"
|
|
|
|
|
|
|
|
|
|
super().__init__(message=error_message)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EnumMetadataNotFound(EnumError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ErrorUploadingFile(FileError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2026-07-14 14:32:05 +04:00
|
|
|
class BlockedInternalUrlError(FileError):
|
|
|
|
|
"""Raised when a URL file input resolves to a non-public network address."""
|
|
|
|
|
|
|
|
|
|
|
2026-04-23 18:42:16 +05:30
|
|
|
class SensitiveFilePathBlockedError(FileError):
|
|
|
|
|
"""Raised when a local file path is refused before upload (sensitive directory or credential-like name)."""
|
|
|
|
|
|
|
|
|
|
|
feat(sdk): default-off auto file upload/download; add dangerouslyAllowAutoUploadDownloadFiles (#3260)
## Summary
Automatic tool file upload/download for `file_uploadable` fields is
**off by default** in TypeScript and Python. Callers must explicitly opt
in, and uploads from local paths are constrained by a fail-closed
allowlist.
## Changes
- **Removed (breaking):** `autoUploadDownloadFiles` (TS) /
`auto_upload_download_files` (Python) — the legacy default-on flag is
gone, not just deprecated.
- **New opt-in:** `dangerouslyAllowAutoUploadDownloadFiles` (TS) /
`dangerously_allow_auto_upload_download_files` (Python). When `true`,
`tools.get(...)` collapses `file_uploadable` schemas to `{ type:
'string', format: 'path' }` and the SDK stages local paths/URLs at
execute time.
- **New:** `fileUploadDirs?: string[] | false` — fail-closed allowlist
for local upload paths. `undefined` → `[<home>/.composio/temp]`; `false`
→ reject all local paths (URLs / `File` objects unaffected); explicit
`string[]` replaces the default. Components are matched on a path
boundary after `realpath`.
- **New:** `fileDownloadDir?: string` — directory where
`file_downloadable` results are staged.
- **New:** `beforeFileUpload` hook receives `source: 'path' | 'url' |
'file'` (TS) / `'path' | 'url'` (Python) so it can branch on input type.
- **New (TS):** when auto-upload is **off** and an LLM-driven
`tools.execute` is called against a tool with `file_uploadable` inputs,
the SDK emits a one-shot warning per tool slug pointing at
`composio.files.upload()` for manual staging.
## Migration
To restore previous behavior:
```ts
new Composio({
apiKey: process.env.COMPOSIO_API_KEY!,
dangerouslyAllowAutoUploadDownloadFiles: true,
// Optional: tighten the allowlist beyond the default ~/.composio/temp
fileUploadDirs: ['/srv/uploads'],
});
```
```python
Composio(api_key="...", dangerously_allow_auto_upload_download_files=True)
```
If you previously passed the legacy flag, remove it. There is no
transitional warning — TS and Python both reject the unknown property at
the type/keyword-arg level.
## Versioning
| Package | Bump |
| ------- | ---- |
| `@composio/core` | minor |
| `composio` (Python) | minor |
| Other `@composio/*` packages | patch (via changesets
`updateInternalDependencies: "patch"`) |
See
`docs/content/changelog/04-24-26-legacy-auto-upload-config-removal.mdx`
for the full migration writeup.
2026-04-28 10:55:03 +05:30
|
|
|
class FileUploadPathNotAllowedError(FileError):
|
|
|
|
|
"""
|
|
|
|
|
Raised when automatic file upload during tool execution is attempted from a
|
|
|
|
|
path outside the configured ``file_upload_dirs`` allowlist.
|
|
|
|
|
|
|
|
|
|
Only fires for auto-upload (enabled via
|
|
|
|
|
``dangerously_allow_auto_upload_download_files=True``). Manual upload APIs
|
|
|
|
|
are not subject to this check.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
2026-04-23 18:42:16 +05:30
|
|
|
class FileUploadAbortedError(FileError):
|
|
|
|
|
"""Raised when a ``before_file_upload`` hook returns ``False``."""
|
|
|
|
|
|
|
|
|
|
|
2026-08-18 13:07:07 +02:00
|
|
|
class UnsafePathComponentError(FileError):
|
|
|
|
|
"""
|
|
|
|
|
Raised when untrusted input (a tool slug, toolkit slug, or server-supplied
|
|
|
|
|
filename) cannot be safely used as part of a filesystem path.
|
|
|
|
|
|
|
|
|
|
Fails closed: the SDK refuses the write rather than sanitizing the value
|
|
|
|
|
into something that merely looks safe.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class ErrorDownloadingFile(FileError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2026-03-10 13:15:48 +05:30
|
|
|
class RemoteFileDownloadError(FileError):
|
|
|
|
|
"""Raised when fetching a remote file from a tool router session mount fails.
|
|
|
|
|
|
|
|
|
|
Includes HTTP status, URL, and file path context for debugging.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
message: str = "Failed to download remote file",
|
|
|
|
|
*,
|
|
|
|
|
status_code: t.Optional[int] = None,
|
|
|
|
|
status_text: t.Optional[str] = None,
|
|
|
|
|
download_url: t.Optional[str] = None,
|
|
|
|
|
mount_relative_path: t.Optional[str] = None,
|
|
|
|
|
filename: t.Optional[str] = None,
|
|
|
|
|
**kwargs: t.Any,
|
|
|
|
|
) -> None:
|
|
|
|
|
super().__init__(message, **kwargs)
|
|
|
|
|
self.status_code = status_code
|
|
|
|
|
self.status_text = status_text
|
|
|
|
|
self.download_url = download_url
|
|
|
|
|
self.mount_relative_path = mount_relative_path
|
|
|
|
|
self.filename = filename
|
|
|
|
|
|
|
|
|
|
|
2026-02-02 20:22:04 +04:00
|
|
|
class ResponseTooLargeError(FileError):
|
|
|
|
|
"""Raised when a response exceeds the maximum allowed size."""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class TriggerError(ToolkitError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-12-13 08:31:57 +01:00
|
|
|
class WebhookSignatureVerificationError(TriggerError):
|
|
|
|
|
"""Raised when webhook signature verification fails."""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WebhookPayloadError(TriggerError):
|
|
|
|
|
"""Raised when webhook payload is invalid."""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
fix(triggers): align create() user_id resolution across SDKs (#3723)
This PR:
- builds on top of https://github.com/ComposioHQ/composio/pull/3714 —
addresses its code-review findings
- restores TS/Python parity on slug validation: Python `create()` now
validates the slug up-front and raises a new `TriggerTypeNotFound`,
mirroring the TS `ComposioTriggerTypeNotFoundError`
- switches both SDKs to the native `user_id` upsert field — TS drops the
`& { user_id }` intersection and Python drops the `extra_body` shim
(both pinned clients already expose the field)
- treats a blank/whitespace `userId` (TS) or
`user_id`/`connected_account_id` (Python) as missing instead of
forwarding it to the backend
- documents the error-contract change (`create()` no longer throws
`ComposioConnectedAccountNotFoundError` — that case now surfaces from
the backend) in the changeset and `ts/docs/api/triggers.md`, and bumps
the changeset from `patch` to `minor`
- adds Python tests for the 2FA (both-provided) path, unknown-slug, and
blank `userId`; tightens the TS auto-resolve assertion and adds an
empty-`userId` case
## ⚠️ Release gating
Since #3714, `triggers.create()` (both SDKs) relies on the backend
resolving the trigger connection from `user_id` on upsert
([ComposioHQ/platform#10932](https://github.com/ComposioHQ/platform/pull/10932)).
There is **no client-side fallback** — reintroducing one would undo
#3714's intent, so this is a release-sequencing requirement, not a code
change here.
- Do not release `@composio/core` or the Python SDK until #10932 is live
in all regions.
- Self-hosted / on-prem deployments must be on a backend version that
includes #10932.
## Review findings addressed
| # | Finding | Resolution |
|---|---------|------------|
| P1-1 | Coupled to unreleased backend, no fallback | Documented
dependency in changeset; flagged release-gating above (no fallback by
design) |
| P2-2 | Cross-SDK parity on slug validation | Kept `getType` in both;
added Python `TriggerTypeNotFound` mirroring TS |
| P2-3 | `user_id` bridge redundant in both SDKs | TS uses native field
directly; Python uses `user_id=` kwarg |
| P2-4 | Error-contract change shipped silently | Documented in
changeset + docs `Throws` section; `minor` bump |
| P2-5 | Python missing 2FA (both-provided) test | Added
`test_create_with_user_id_and_connected_account_id` |
| P3 6–13 | Cleanups | undefined-assertion, `none_to_omit`, docstring,
`parsedBody.data`, redundant `else`, stale comments, blank-string guard
|
## Verification
- TS: `vitest` 59 passed, `typecheck` clean, `eslint`/`prettier` clean
- Python: `pytest tests/test_triggers.py` 69 passed, `nox -s chk` (ruff
+ mypy) clean
2026-07-02 11:40:47 +04:00
|
|
|
class TriggerTypeNotFound(TriggerError, NotFoundError):
|
|
|
|
|
"""Raised when a trigger type cannot be found for the given slug.
|
|
|
|
|
|
|
|
|
|
Mirrors the TypeScript SDK's ``ComposioTriggerTypeNotFoundError``.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class ActionError(ToolkitError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TriggerSubscriptionError(TriggerError, ComposioClientError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidTriggerFilters(TriggerSubscriptionError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
fix(sdk): harden pusher auth and cross-origin redirect headers (#4406)
This PR:
- wraps `pysher.Pusher` in `_ComposioPusher`, whose channel-auth POST
carries a `(5, 15)` connect/read timeout and raises
`TriggerSubscriptionAuthError` (a `TriggerSubscriptionError`) on a
transport failure, a non-200, or a response without an `auth` token —
pysher 1.0.8 sent it with no timeout and turned a non-200 into a bare
`AssertionError` on the websocket thread, on every (re)subscribe
- keeps that POST a plain `requests.post(..., timeout=...)` rather than
routing it through `safe_request`: the endpoint is built from the
configured Composio API base URL, a fixed trusted host, not a value from
a response, and the SSRF guard would refuse a local dev base URL
- validates `pusher_cluster` against `^[a-z0-9-]+$` (non-empty, at most
64 chars) before pysher formats it into `ws-{cluster}.pusher.com`,
raising `InvalidPusherClusterError` that names the shape violation
without echoing the value
- replaces the `unittest.mock.MagicMock` stand-in for pysher's
connection logger with a dedicated `logging.Logger` (`NullHandler`,
`propagate=False`, disabled), so `unittest` leaves the runtime import
graph while raw frames stay out of user logs; a test asserts the module
source no longer mentions `unittest`
- strips `Authorization`, `Proxy-Authorization`, and `Cookie` from the
next hop when `ssrfSafeFetch` or `safe_request` follows a redirect to a
different origin; same-origin hops keep them. Manual redirect following
bypasses both `fetch`'s cross-origin rule and `requests`'
`rebuild_auth`, so neither guard applied it before — the gap #4387 left
out
- `@composio/slim` has no mirrored source (its build copies
`core/dist`), so the changeset covers `@composio/core` and
`@composio/slim` as patches
Verified with `pytest tests/test_triggers.py tests/test_url_safety.py
tests/test_path_join_guardrail.py` (192 passed), `ruff check` / `ruff
format --check` on the changed files, `mypy --config-file
config/mypy.ini` on the three changed modules with the noxfile's stub
pins (no issues), `vitest run test/utils/ssrfGuard.test.ts` in
`@composio/core` (42 passed), `pnpm typecheck` at the root (14 tasks
successful), and `oxlint` + `prettier --check` on the changed TypeScript
files.
https://claude.ai/code/session_016ZuBv7JhVdSYTLYcTy2VJr
2026-09-09 21:29:18 +02:00
|
|
|
class TriggerSubscriptionAuthError(TriggerSubscriptionError):
|
|
|
|
|
"""Raised when the realtime channel-auth request fails.
|
|
|
|
|
|
|
|
|
|
Covers a transport error, a timeout, a non-200 response, and a response
|
|
|
|
|
without an ``auth`` token.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidPusherClusterError(TriggerSubscriptionError, ValidationError):
|
|
|
|
|
"""Raised when the realtime credentials carry a malformed pusher cluster."""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class ApiKeyError(ComposioClientError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ApiKeyNotProvidedError(ApiKeyError, NotFoundError):
|
|
|
|
|
"""Raise when API key is required but not provided."""
|
|
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
super().__init__(
|
|
|
|
|
message=(
|
|
|
|
|
"API Key not provided, either provide API key "
|
|
|
|
|
f"or export it as `{ENV_COMPOSIO_API_KEY}` "
|
|
|
|
|
"or run `composio login`"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResourceError(ComposioClientError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NoItemsFound(ResourceError):
|
|
|
|
|
"""
|
|
|
|
|
Exception class for empty collection values.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ErrorFetchingResource(ResourceError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SchemaError(ToolkitError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidSchemaError(SchemaError, TypeError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidEntityIdError(EntityIDError, ValueError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class IntegrationError(ResourceError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectedAccountError(ResourceError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectedAccountNotFoundError(NotFoundError, ConnectedAccountError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidConnectedAccount(ValidationError, ConnectedAccountError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-09-29 15:37:53 +05:30
|
|
|
class ComposioMultipleConnectedAccountsError(ConnectedAccountError):
|
|
|
|
|
"""Raised when multiple connected accounts are found for a user and auth config."""
|
2025-09-29 15:59:28 +05:30
|
|
|
|
2025-09-29 15:37:53 +05:30
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2026-04-25 18:12:30 +05:30
|
|
|
class ComposioLegacyConnectedAccountsEndpointRetiredError(ConnectedAccountError):
|
|
|
|
|
"""Raised by ``composio.connected_accounts.initiate()`` when the legacy
|
|
|
|
|
``POST /api/v3/connected_accounts`` endpoint rejects a Composio-managed
|
|
|
|
|
OAuth (OAuth1, OAuth2, DCR_OAUTH) auth-config request.
|
|
|
|
|
|
|
|
|
|
Cutover dates: 2026-05-08 (new orgs), 2026-07-03 (all remaining orgs).
|
|
|
|
|
Migrate to ``composio.connected_accounts.link()`` — same return shape,
|
|
|
|
|
works for every redirectable scheme regardless of whether the auth
|
|
|
|
|
config is Composio-managed or custom.
|
|
|
|
|
|
|
|
|
|
See: https://docs.composio.dev/docs/changelog/2026/04/24
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
class ComposioAclOnlyForSharedError(ConnectedAccountError):
|
|
|
|
|
"""Raised when ACL fields (``allow_all_users``, ``allowed_user_ids``,
|
2026-05-12 01:28:00 +05:30
|
|
|
``not_allowed_user_ids``) are sent on a ``PRIVATE`` connection. ACL
|
|
|
|
|
is only meaningful for ``SHARED`` connections.
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
|
2026-05-12 01:28:00 +05:30
|
|
|
Fix: use ``account_type='SHARED'``, or omit the ACL fields when
|
|
|
|
|
creating/updating a PRIVATE connection.
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ComposioSharedAccessDeniedError(ConnectedAccountError):
|
|
|
|
|
"""Raised when a tool execution attempts to use a SHARED connected
|
|
|
|
|
account but the requesting ``user_id`` is not allowed by the
|
|
|
|
|
connection's ACL.
|
|
|
|
|
|
2026-05-12 01:21:10 +05:30
|
|
|
Surfaces when a SHARED connection is reached directly (e.g. via
|
|
|
|
|
``composio.tools.execute(slug, connected_account_id=...)``) without
|
|
|
|
|
going through a tool-router session.
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
|
|
|
|
|
Fix: ask the connection's creator to grant access via
|
2026-05-13 18:22:07 +05:30
|
|
|
``composio.experimental.update_acl()`` — set ``allow_all_users``,
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
add the ``user_id`` to ``allowed_user_ids``, or remove it from
|
|
|
|
|
``not_allowed_user_ids``.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ComposioSharedConnectionNotAccessibleError(ConnectedAccountError):
|
2026-05-12 01:28:00 +05:30
|
|
|
"""Raised by ``tool_router.session.create()`` / ``session.patch()``
|
|
|
|
|
when the session's ``user_id`` cannot use a pinned SHARED connection.
|
|
|
|
|
Raised at session-create time so the session never enters a state
|
|
|
|
|
that fails mid-execution.
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
|
|
|
|
|
Fix: grant the session user access via
|
2026-05-13 18:22:07 +05:30
|
|
|
``composio.experimental.update_acl()`` on the pinned connection,
|
feat(connected-accounts-py): surface account_type + per-user ACL on SHARED connections
Python mirror of #3392 (TypeScript SDK). Same Apollo-side feature shipped
across four Hermes PRs (#9860, #9882, #9887 internal, #9902), now exposed
through @composio/* Python SDK wrappers.
Bumped composio-client 1.37.0 → 1.38.0 (the regenerated client published
by composio-base-py#66 — contains account_type + acl_config_for_shared on
LinkCreateParams, ConnectedAccountPatchParams, SessionLinkParams, the
retrieve response, and the list response item).
SDK changes:
- composio.connected_accounts.link() now accepts `account_type` and
`acl_config_for_shared`. Default behaviour (omit both) creates a
PRIVATE connection exactly as before.
- New composio.connected_accounts.update_acl(nanoid, *, allow_all_users,
allowed_user_ids, not_allowed_user_ids) — wraps PATCH /connected_accounts/{id}
with the same semantics as the TS sibling. PATCH semantics: omit a
param to leave unchanged; pass [] to clear an allow/deny list. Raises
ValidationError if all three are None.
- composio.tool_router_session.authorize() options gain `account_type`
and `acl_config_for_shared` — the /tool_router/session/{id}/link
endpoint accepts the same fields.
- New typed errors in composio.exceptions:
* ComposioAclOnlyForSharedError (400) — wired at link() / update_acl()
/ authorize() catch sites via the same
`acl_config_for_shared is only valid on SHARED` substring match used
in the TS SDK. Verified against Apollo's createConnectedAccount.ts.
* ComposioSharedAccessDeniedError (403) — exported, not yet wrapped.
Wraps when Tools.execute() error mapping lands in a follow-up.
* ComposioSharedConnectionNotAccessibleError (400) — exported, not
yet wrapped. Wraps when ToolRouterSession.create()/patch() session-
validator error mapping lands.
Plumbing:
- python/composio/client/types.py re-exports `link_create_params` (the
generated client's TypedDicts for link create payloads, including
`ACLConfigForShared`).
Tests: 12 new tests in TestConnectedAccountsAcl class covering link()
ACL forwarding (4), AclOnlyForShared mapping on link() (1), pass-through
of unrelated BadRequestError (1), update_acl() body construction (3),
empty-fields rejection (1), AclOnlyForShared mapping on update_acl() (1),
pass-through of unrelated BadRequestError on update_acl() (1). 49 tests
pass (37 pre-existing + 12 new); full suite 635 pass / 31 skipped.
Verified: nox -s chk clean (ruff + mypy on src + tests).
Version: 0.13.0 → 0.14.0 (minor — additive surface).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 00:20:01 +05:30
|
|
|
or pin a different connection the user can use.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class ErrorProcessingToolExecutionRequest(PluginError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DescopeAuthError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DescopeConfigError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidExecuteFunctionError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2026-09-11 22:54:53 +02:00
|
|
|
class ToolNotFoundError(NotFoundError):
|
|
|
|
|
"""Raised when a tool slug does not exist.
|
|
|
|
|
|
|
|
|
|
Mirrors the TypeScript SDK's ``ComposioToolNotFoundError``. Other failures
|
|
|
|
|
while fetching a tool (invalid API key, server or network errors) are not
|
|
|
|
|
translated and surface as the underlying ``composio_client`` error.
|
|
|
|
|
"""
|
2025-06-17 12:58:00 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidModifier(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ExecuteToolFnNotSetError(ComposioError):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2025-10-22 11:01:50 +05:30
|
|
|
class ToolVersionRequiredError(ComposioError):
|
|
|
|
|
"""Raised when toolkit version is not specified for manual tool execution."""
|
|
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
super().__init__(
|
|
|
|
|
message=(
|
|
|
|
|
"Toolkit version not specified. For manual execution of the tool "
|
|
|
|
|
"please pass a specific toolkit version.\n\n"
|
|
|
|
|
"Possible fixes:\n"
|
|
|
|
|
"1. Pass the toolkit version as a parameter to the execute function "
|
|
|
|
|
'("latest" is not supported in manual execution)\n'
|
|
|
|
|
"2. Set the toolkit versions in the Composio config "
|
|
|
|
|
"(toolkit_versions={'<toolkit-slug>': '<toolkit-version>'})\n"
|
|
|
|
|
"3. Set the toolkit version in the environment variable "
|
|
|
|
|
"(COMPOSIO_TOOLKIT_VERSION_<TOOLKIT_SLUG>)\n"
|
|
|
|
|
"4. Set dangerously_skip_version_check to True "
|
|
|
|
|
"(this might cause unexpected behavior when new versions of the tools are released)"
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 12:58:00 +05:30
|
|
|
class UsageError(ComposioError):
|
|
|
|
|
pass
|