Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/content/docs/agentkit/sdks/node/errors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,51 @@ try {

`ScalekitServerException` is the base type. Prefer checking subclasses first so not-found and auth failures get the right UX.

## Tool execution errors

A failure during `scalekit.tools.executeTool` comes from one of two places, and the fix differs for each:

- **The upstream provider rejected the call** (Gmail, Slack, Salesforce, and so on). Scalekit raises a dedicated `ScalekitTool*` exception. The most common is `ScalekitToolUnauthorizedException`, which means the connected account's provider token was expired or revoked — re-authorize the connected account. Do not change your client credentials.
- **Scalekit rejected the call.** A plain `ScalekitUnauthorizedException` (no tool details) means your `client_id`/`client_secret` or Scalekit token is invalid. The SDK already refreshed and retried before surfacing it, so fix the credentials.

Each tool exception subclasses its plain counterpart — `ScalekitToolUnauthorizedException` extends `ScalekitUnauthorizedException` — so **catch the tool type first**. Use `isToolException()` to detect any upstream tool failure, and read `toolErrorCode`, `toolErrorMessage`, and `executionId` for logging.

```ts wrap showLineNumbers=false
import {
ScalekitToolUnauthorizedException,
ScalekitToolRateLimitException,
ScalekitUnauthorizedException,
isToolException,
} from '@scalekit-sdk/node'

try {
const result = await scalekit.tools.executeTool({
toolName: 'gmail_send_email',
identifier: 'user@example.com',
})
} catch (err) {
if (err instanceof ScalekitToolUnauthorizedException) {
// Upstream provider rejected the token — re-authorize the connected account
} else if (err instanceof ScalekitToolRateLimitException) {
// Upstream provider rate limit — back off, then retry the tool call
} else if (err instanceof ScalekitUnauthorizedException) {
// Scalekit-side credentials are invalid — fix client ID/secret
} else if (isToolException(err)) {
// Any other upstream tool failure — inspect the provider's error code
console.error(err.toolErrorCode, err.executionId)
Comment on lines +65 to +89

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- tracked candidate files ---'
git ls-files 'src/content/docs/agentkit/sdks/node/errors.mdx' \
  'src/content/docs/agentkit/sdks/python/errors.mdx' \
  'src/content/docs/agentkit/**' | sed -n '1,120p'

printf '%s\n' '--- node errors.mdx ---'
sed -n '1,130p' src/content/docs/agentkit/sdks/node/errors.mdx

printf '%s\n' '--- python errors.mdx ---'
sed -n '1,130p' src/content/docs/agentkit/sdks/python/errors.mdx

printf '%s\n' '--- repository references to the claimed fields ---'
rg -n --glob '!node_modules' \
  'tool(ErrorMessage|_error_message)|toolErrorCode|tool_error_code|executionId|execution_id' \
  src/content src README.md 2>/dev/null | sed -n '1,240p'

printf '%s\n' '--- external repository metadata ---'
curl -L --fail --silent --show-error \
  https://api.github.com/repos/scalekit-developers/agent-auth-examples/contents \
  | jq -r '.[] | [.type, .path, .download_url] | `@tsv`' | sed -n '1,160p'

Repository: scalekit-inc/developer-docs

Length of output: 21010


🌐 Web query:

Search the public scalekit-developers/agent-auth-examplesrepository and current Scalekit AgentKit Node.js and Python SDK documentation forScalekitToolException, toolErrorMessage, tool_error_message, toolErrorCode, tool_error_code, executionId, and execution_id. Identify the current diagnostic fields and example logging behavior.

💡 Result:

In the Scalekit AgentKit ecosystem, diagnostic fields and error handling are managed through a specific hierarchy of exceptions and identifiers. Diagnostic Fields and Identifiers Execution IDs are consistently represented as executionId (typically CamelCase in Node.js/TypeScript SDKs and related metadata) [1][2][3][4]. While execution_id is sometimes used in YAML-based configurations or frontmatter [1][2][5], the SDK interfaces primarily expose executionId. Error Handling and Diagnostic Exceptions Scalekit uses a typed exception hierarchy to handle tool execution failures, centralizing diagnostics through ScalekitToolException [6]. This exception hierarchy allows for granular error handling: 1. ScalekitToolRateLimitException: Specifically handles provider 429 errors [6]. 2. ScalekitToolUnauthorizedException: Specifically handles provider 401 errors [6]. 3. ScalekitToolForbiddenException: Specifically handles provider 403 errors [6]. 4. ScalekitToolException: The base class for other provider errors, extending ScalekitServerException [6]. These exceptions facilitate diagnostic logging by allowing developers to differentiate between provider-level issues and general API failures. The isToolException(e) type guard is available to catch all provider-related errors collectively [6]. Logging and Diagnostic Behavior Diagnostic information is accessed through both explicit SDK methods and dashboard logs: - SDK Diagnostics: For tool execution, logs generally surface through the result of scalekit.actions.executeTool [7]. If a tool call fails, the error message often points to scopes, credentials, or provider rate limits [7]. - Dashboard Logs: The Scalekit dashboard provides a centralized view for monitoring, where users can review connected account status, refresh history, and tool execution logs [7]. - Behavior Note: A key recent change in Scalekit SDK behavior is that provider errors (including 429s) are no longer retried automatically by the SDK; they surface immediately to allow the caller to manage their own retry strategy [6]. Note: While queries for toolErrorMessage, tool_error_message, toolErrorCode, and tool_error_code were performed, these fields do not appear as standard, first-class diagnostic properties within the official Scalekit AgentKit SDK interfaces; rather, diagnostic details are extracted from the structured exception hierarchy or the return data of execution methods [6][7].

Citations:


🌐 Web query:

Open and summarize https://github.com/scalekit-inc/scalekit-sdk-node/pull/200 and the current scalekit-inc/scalekit-sdk-nodesource. Focus on the definitions ofScalekitToolException, ScalekitToolUnauthorizedException, isToolException, toolErrorCode, toolErrorMessage, and executionId, including whether these properties are public and intended for logging.

💡 Result:

The scalekit-sdk-node library introduced a new exception hierarchy for tool execution errors in Pull Request #200 [1]. These additions are designed to improve error differentiation, specifically separating errors originating from upstream providers from those caused by Scalekit itself [1]. Definitions and usage: - ScalekitToolException: The base exception class for provider-side errors, extending ScalekitServerException [1]. It represents generic provider errors that occur during tool execution [1]. - ScalekitToolUnauthorizedException: A specific subclass of ScalekitUnauthorizedException, triggered when an upstream provider returns a 401 status [1]. Unlike general authentication failures, this surfaces immediately without automatic token refresh attempts [1]. - isToolException(e): A type guard function used to identify if an error is a provider-side "tool error" [1][2]. It allows developers to check for these specific errors in a single catch block, which is essential for distinguishing provider rate limits or auth issues from Scalekit's own platform errors [1][3]. - toolErrorCode and toolErrorMessage: These properties are associated with the underlying error details [1][3]. The SDK extracts these from the response when a tool execution fails [1][2]. They are intended for developers to inspect the nature of the provider error (e.g., identifying if a 429 was caused by a TOOL_ERROR or a platform RATE_LIMITED issue) to implement correct backoff strategies [3]. - executionId: While not explicitly defined as a top-level property of the exception classes in the summary of PR #200, execution-related information is typically surfaced through the error details and the broader Scalekit logging/audit infrastructure to help track tool-calling flows [1][4]. Regarding logging and publicity, these exception properties are public, typed, and intended for developer consumption in error-handling blocks [1][5][3]. They provide the necessary context to debug why a tool call failed—whether due to provider-side permissions, rate limits, or connectivity—making them suitable for structured logging in applications that manage agent tool calls [3][4]. Developers are encouraged to use these typed exceptions instead of parsing raw error strings to ensure robust and backward-compatible error handling [1][5].

Citations:


🌐 Web query:

Search the public Scalekit Python SDK source and documentation for ScalekitToolException, ScalekitToolUnauthorizedException, tool_error_code, tool_error_message, and execution_id. Determine which properties exist on the exceptions and how current examples handle them.

💡 Result:

In the Scalekit Python SDK, ScalekitToolException and ScalekitToolUnauthorizedException are part of an exception hierarchy designed to handle tool execution failures [1]. While these specific classes are prominently featured in the Node.js SDK's recent architectural updates [1], they reflect the underlying error structure used across Scalekit's platforms [2]. Properties such as tool_error_code, tool_error_message, and execution_id originate from the Scalekit API's tool execution response structure [2][3]. When a tool execution fails, these fields are typically provided within the error context [2]. Key findings regarding these properties and exceptions: 1. Exception Hierarchy: Scalekit uses a typed exception hierarchy to handle tool errors, where ScalekitToolUnauthorizedException typically extends an unauthorized base exception, and ScalekitToolException covers general provider-side errors [1]. These exceptions allow for granular error differentiation—such as distinguishing between a provider-side rate limit and a general execution failure—enabling more precise retry and recovery strategies [4][1]. 2. Error Properties: The fields tool_error_code, tool_error_message, and execution_id are standard components returned by the Scalekit API when a tool call fails [2]. - execution_id: A unique identifier for the specific tool execution attempt, useful for tracing and debugging [2][3]. - tool_error_code: A machine-readable code (e.g., TOOL_ERROR) identifying the specific nature of the failure [4][2]. - tool_error_message: A human-readable description of the error [4][2]. 3. Handling in SDKs: Current SDK implementations emphasize extracting these details to avoid blind retries [1]. For example, in rate-limiting scenarios, SDK users can inspect the error code to decide whether to apply provider-specific backoff or general request frequency reduction [4]. When building integrations, developers should check for these fields within exception objects to provide actionable feedback, such as clarifying input schema requirements when a field-level validation error occurs [5][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

printf '%s\n' '--- Node SDK PR patch references ---'
curl -L --fail --silent --show-error \
  https://github.com/scalekit-inc/scalekit-sdk-node/pull/200.patch \
  -o "$tmpdir/node.patch"
rg -n -C 5 \
  'ScalekitToolException|ScalekitToolUnauthorizedException|isToolException|toolErrorCode|toolErrorMessage|executionId' \
  "$tmpdir/node.patch" | sed -n '1,260p'

printf '%s\n' '--- Node SDK commit tree candidates ---'
curl -L --fail --silent --show-error \
  https://github.com/scalekit-inc/scalekit-sdk-node/commit/a96e36a4f6722d16c56bffec5e9827843a62ceab.patch \
  -o "$tmpdir/node-commit.patch"
rg -n -C 5 \
  'ScalekitToolException|ScalekitToolUnauthorizedException|isToolException|toolErrorCode|toolErrorMessage|executionId' \
  "$tmpdir/node-commit.patch" | sed -n '1,260p'

printf '%s\n' '--- Python SDK public repository refs ---'
git ls-remote https://github.com/scalekit-inc/scalekit-sdk-python.git \
  'refs/heads/*' 'refs/tags/*' | sed -n '1,80p'

printf '%s\n' '--- Agent examples repository refs ---'
git ls-remote https://github.com/scalekit-developers/agent-auth-examples.git \
  'refs/heads/*' 'refs/tags/*' | sed -n '1,80p'

Repository: scalekit-inc/developer-docs

Length of output: 19007


🏁 Script executed:

#!/bin/bash
set -eu

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -L --fail --silent --show-error \
  https://codeload.github.com/scalekit-inc/scalekit-sdk-python/tar.gz/1f635128c04374ec82a1088469c20182dbcec457 \
  -o "$tmpdir/python.tgz"
mkdir "$tmpdir/python"
tar -xzf "$tmpdir/python.tgz" -C "$tmpdir/python"

printf '%s\n' '--- Python exception source paths ---'
find "$tmpdir/python" -type f | rg '/(exception|exceptions|error|errors)(/|\.|$)' | sed -n '1,120p'

printf '%s\n' '--- Python exception field definitions and usage ---'
rg -n -C 5 \
  'ScalekitToolException|ScalekitToolUnauthorizedException|tool_error_code|tool_error_message|execution_id' \
  "$tmpdir/python" | sed -n '1,320p'

curl -L --fail --silent --show-error \
  https://codeload.github.com/scalekit-developers/agent-auth-examples/tar.gz/f1723f3ae184acac816dfed79a2429bdd07d1acd \
  -o "$tmpdir/examples.tgz"
mkdir "$tmpdir/examples"
tar -xzf "$tmpdir/examples.tgz" -C "$tmpdir/examples"

printf '%s\n' '--- AgentKit example error-handling paths ---'
rg -n -C 5 \
  'ScalekitToolException|ScalekitToolUnauthorizedException|tool(ErrorCode|ErrorMessage)|tool_(error_code|error_message)|execution(Id|_id)|isToolException' \
  "$tmpdir/examples" | sed -n '1,320p'

Repository: scalekit-inc/developer-docs

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -eu

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -L --fail --silent --show-error \
  https://codeload.github.com/scalekit-developers/agent-auth-examples/tar.gz/f1723f3ae184acac816dfed79a2429bdd07d1acd \
  -o "$tmpdir/examples.tgz"
mkdir "$tmpdir/examples"
tar -xzf "$tmpdir/examples.tgz" -C "$tmpdir/examples"

printf '%s\n' '--- external example files containing tool error handling ---'
rg -l \
  'ScalekitToolException|ScalekitToolUnauthorizedException|tool(ErrorCode|ErrorMessage)|tool_(error_code|error_message)|isToolException' \
  "$tmpdir/examples" | sed -n '1,120p'

printf '%s\n' '--- external example diagnostic lines ---'
rg -n \
  'ScalekitToolException|ScalekitToolUnauthorizedException|tool(ErrorCode|ErrorMessage)|tool_(error_code|error_message)|execution(Id|_id)|isToolException' \
  "$tmpdir/examples" | sed -n '1,180p'

printf '%s\n' '--- concise Python SDK definition ---'
curl -L --fail --silent --show-error \
  https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/1f635128c04374ec82a1088469c20182dbcec457/scalekit/common/exceptions.py \
  | sed -n '293,325p'

printf '%s\n' '--- documentation invariant check ---'
python3 - <<'PY'
from pathlib import Path

cases = {
    Path("src/content/docs/agentkit/sdks/node/errors.mdx"): (
        "toolErrorCode", "toolErrorMessage", "executionId",
        "console.error(err.toolErrorCode, err.executionId)",
    ),
    Path("src/content/docs/agentkit/sdks/python/errors.mdx"): (
        "tool_error_code", "tool_error_message", "execution_id",
        "print(e.tool_error_code, e.execution_id)",
    ),
}
for path, (code, message, execution, log_line) in cases.items():
    text = path.read_text()
    assert code in text and message in text and execution in text
    assert log_line in text
    print(f"{path}: documented={code,message,execution}; current_log_omits_message=True")
PY

Repository: scalekit-inc/developer-docs

Length of output: 2023


Log the provider error message.

Both examples document the provider message field but log only the error code and execution ID. Include err.toolErrorMessage and e.tool_error_message in the diagnostic output.

📍 Affects 2 files
  • src/content/docs/agentkit/sdks/node/errors.mdx#L65-L89 (this comment)
  • src/content/docs/agentkit/sdks/python/errors.mdx#L63-L89
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/content/docs/agentkit/sdks/node/errors.mdx` around lines 65 - 89, Update
the diagnostic logging in the Node example’s isToolException() branch to include
err.toolErrorMessage alongside toolErrorCode and executionId. Also update the
Python example at src/content/docs/agentkit/sdks/python/errors.mdx lines 63-89
to include e.tool_error_message alongside the existing provider error fields.

} else {
throw err
}
}
```
Comment on lines +67 to +94

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -u

for file in \
  src/content/docs/agentkit/sdks/node/errors.mdx \
  src/content/docs/agentkit/sdks/python/errors.mdx
do
  echo "===== $file ====="
  sed -n '1,125p' "$file"
done

echo "===== AgentKit references ====="
rg -n --hidden -S \
  'toolErrorMessage|tool_error_message|ScalekitToolUnauthorizedException|ScalekitToolRateLimitException|isToolException|<Code|from .+Code' \
  src/content/docs/agentkit \
  2>/dev/null || true

echo "===== Repository files related to AgentKit examples ====="
git ls-files | rg -i 'agent.?auth|agentkit|errors\.mdx' | head -200

Repository: scalekit-inc/developer-docs

Length of output: 23984


🏁 Script executed:

#!/bin/bash
set -u

echo "===== Local <Code> conventions ====="
rg -n -U '<Code[\s\S]{0,250}(title=|lang=)|import \{? ?Code|from .+Code' src/content/docs src/components | head -200

echo "===== External AgentKit example repository ====="
curl -fsSL \
  https://api.github.com/repos/scalekit-developers/agent-auth-examples/git/trees/main?recursive=1 \
  | jq -r '.tree[]?.path' \
  | rg -i 'error|exception|agentkit|node|python' \
  | head -200

echo "===== External repository metadata ====="
curl -fsSL https://api.github.com/repos/scalekit-developers/agent-auth-examples \
  | jq -r '{default_branch, html_url, archived}'

Repository: scalekit-inc/developer-docs

Length of output: 5770


🌐 Web query:

site:github.com/scalekit-developers/agent-auth-examples AgentKit errors ScalekitToolUnauthorizedException

💡 Result:

There is no official record of an error named ScalekitToolUnauthorizedException in the Scalekit AgentKit documentation or associated repositories [1][2][3][4]. Errors related to unauthorized access in AgentKit generally manifest as standard HTTP 401 Unauthorized responses or specific diagnostic messages when a connector or connected account is not properly authorized [5][6][7]. If you encounter authorization issues while using AgentKit, consider the following troubleshooting steps: 1. Check Authorization Status: AgentKit flows typically print an authorization link in the logs if a user has not yet authorized access [1]. Follow this link to complete the OAuth flow [1][7]. 2. Verify Connected Accounts: Ensure that the specific connected account (the per-user instance of a connection) has been created and is in an active state in the Scalekit Dashboard [2]. 3. Validate Token Lifecycle: Scalekit handles OAuth token storage and automatic refresh [1][2]. If you are manually handling credentials, ensure that your tokens are not expired and that your application logic correctly handles the 401 Unauthorized response by triggering a re-authorization or refresh flow [5][6]. 4. Check Connector Configuration: Ensure that the credentials (such as API keys or OAuth client details) stored in your Scalekit connection configuration are valid and have the necessary scopes to perform the requested tool actions [2][5]. If you are seeing a specific exception name in your code that is not listed in the official documentation, it is possible that it is a custom exception class implemented within your specific application or a wrapper library rather than a core AgentKit SDK exception [8][4]. Check your local codebase for the definition of this exception to determine where it is being raised.

Citations:


🌐 Web query:

"ScalekitToolUnauthorizedException" "agent-auth-examples"

💡 Result:

The ScalekitToolUnauthorizedException is a specific typed exception in the Scalekit SDK that indicates a 401 Unauthorized error occurred during a tool execution, typically originating from the third-party provider being accessed (e.g., Gmail, Slack, Notion) [1]. This exception is part of an error hierarchy designed to distinguish between SDK-level issues and provider-specific failures [1]. Unlike general authentication errors that might trigger an automatic token refresh, a ScalekitToolUnauthorizedException signifies that the provider itself has rejected the request, often due to an invalid, expired, or revoked access token, and it is raised immediately to prevent unnecessary retry amplification [1]. The agent-auth-examples repository (available at github.com/scalekit-developers/agent-auth-examples) serves as the official source for examples demonstrating how to use Scalekit’s authentication lifecycle [2][3]. These examples showcase how to: 1. Manage the OAuth flow (authorization, token storage, and automatic refresh) so agents can act on behalf of users [2][4]. 2. Use connected accounts to handle authentication consistently across different providers [4]. 3. Implement error handling patterns to catch typed exceptions, including those related to tool execution [5][6][7]. When encountering a ScalekitToolUnauthorizedException, it is recommended to: - Verify the connected account status using get_connected_account [8]. - Refresh the connected account credentials if necessary using refresh_connected_account [8]. - Ensure the scopes required by the tool match the scopes granted during the user's initial authorization flow [8].

Citations:


🌐 Web query:

site:github.com/scalekit-developers/agent-auth-examples "execute_tool" "tool_error_code"

💡 Result:

No indexed GitHub results were found for:

site:github.com/scalekit-developers/agent-auth-examples "execute_tool" "tool_error_code"

The repository or those exact terms may not be publicly indexed.


Use titled <Code> samples

Import Code once in each file and replace the untitled fenced samples with <Code> components. Set each title to the example file path.

  • src/content/docs/agentkit/sdks/node/errors.mdx:67-94
  • src/content/docs/agentkit/sdks/python/errors.mdx:65-90
📍 Affects 2 files
  • src/content/docs/agentkit/sdks/node/errors.mdx#L67-L94 (this comment)
  • src/content/docs/agentkit/sdks/python/errors.mdx#L65-L90
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/content/docs/agentkit/sdks/node/errors.mdx` around lines 67 - 94, Import
the Code component once in src/content/docs/agentkit/sdks/node/errors.mdx and
replace the untitled fenced sample around lines 67-94 with Code, setting its
title to the example file path. Apply the same change in
src/content/docs/agentkit/sdks/python/errors.mdx around lines 65-90, using that
sample’s example file path as the title.

Sources: Coding guidelines, Path instructions


| Exception | When it is raised | Typical response |
| --- | --- | --- |
| `ScalekitToolUnauthorizedException` | Upstream provider returned 401 during tool execution | Re-authorize the connected account |
| `ScalekitToolForbiddenException` | Upstream provider returned 403 during tool execution | Add the missing provider scope, then re-authorize |
| `ScalekitToolRateLimitException` | Upstream provider returned 429 during tool execution | Back off and retry the tool call |
| `ScalekitToolException` | Any other upstream provider error during tool execution | Log `toolErrorCode` and `executionId`; surface a clear message |
Comment on lines +60 to +101

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

examples_dir="$(mktemp -d)"
trap 'rm -rf "$examples_dir"' EXIT

git clone --depth=1 https://github.com/scalekit-developers/agent-auth-examples.git "$examples_dir"

rg -n -C 4 \
  'executeTool|execute_tool|isToolException|ScalekitTool[A-Za-z]+Exception|toolError(Code|Message)|tool_error_(code|message)|execution(Id|_id)|refresh|retry' \
  "$examples_dir"

Repository: scalekit-inc/developer-docs

Length of output: 23077


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- local documentation ---'
sed -n '1,140p' src/content/docs/agentkit/sdks/node/errors.mdx
sed -n '1,135p' src/content/docs/agentkit/sdks/python/errors.mdx

printf '%s\n' '--- local SDK and exception references ---'
rg -n -C 3 \
  'ScalekitTool|isToolException|toolError(Code|Message)|tool_error_(code|message)|execution(Id|_id)|executeTool|execute_tool|tools\.execute|actions\.execute|refresh.*retry|retry.*refresh' \
  --glob '!src/content/docs/agentkit/sdks/node/errors.mdx' \
  --glob '!src/content/docs/agentkit/sdks/python/errors.mdx' .

printf '%s\n' '--- current AgentKit examples ---'
examples_dir="$(mktemp -d)"
trap 'rm -rf "$examples_dir"' EXIT
git clone --depth=1 https://github.com/scalekit-developers/agent-auth-examples.git "$examples_dir" >/dev/null
rg -n -C 5 \
  'executeTool|execute_tool|isToolException|ScalekitTool[A-Za-z]+Exception|toolError(Code|Message)|tool_error_(code|message)|execution(Id|_id)|refresh|retry' \
  "$examples_dir"

Repository: scalekit-inc/developer-docs

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- node errors page ---'
nl -ba src/content/docs/agentkit/sdks/node/errors.mdx | sed -n '50,115p'

printf '%s\n' '--- python errors page ---'
nl -ba src/content/docs/agentkit/sdks/python/errors.mdx | sed -n '48,110p'

printf '%s\n' '--- focused local AgentKit references ---'
rg -n -C 2 \
  'ScalekitTool|isToolException|toolError(Code|Message)|tool_error_(code|message)|execution(Id|_id)|executeTool|execute_tool|actions\.execute|tools\.execute|refresh|retry' \
  src/content/docs/agentkit src/components/templates/agent-connectors \
  -g '*.mdx' -g '*.md' | head -n 500

printf '%s\n' '--- external example files and focused calls ---'
examples_dir="$(mktemp -d)"
trap 'rm -rf "$examples_dir"' EXIT
git clone --depth=1 https://github.com/scalekit-developers/agent-auth-examples.git "$examples_dir" >/dev/null
find "$examples_dir" -maxdepth 4 -type f | sort | sed -n '1,220p'
rg -n -C 4 \
  'executeTool|execute_tool|ScalekitTool|isToolException|toolError|tool_error|executionId|execution_id|refresh|retry' \
  "$examples_dir/javascript" "$examples_dir/python" | head -n 800

printf '%s\n' '--- repository package and lock references ---'
rg -n -C 2 \
  '`@scalekit-sdk/node`|scalekit.*python|agentkit|ScalekitUnauthorizedException|ScalekitToolException' \
  package.json pnpm-lock.yaml . \
  -g 'package.json' -g 'pyproject.toml' -g 'requirements*.txt' -g 'pnpm-lock.yaml' \
  -g '!src/content/**' -g '!src/components/**' 2>/dev/null | head -n 300

Repository: scalekit-inc/developer-docs

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- node errors page ---'
sed -n '50,115p' src/content/docs/agentkit/sdks/node/errors.mdx | awk '{printf "%4d  %s\n", NR+49, $0}'

printf '%s\n' '--- python errors page ---'
sed -n '48,110p' src/content/docs/agentkit/sdks/python/errors.mdx | awk '{printf "%4d  %s\n", NR+47, $0}'

printf '%s\n' '--- focused local references ---'
rg -n -C 2 \
  'ScalekitTool|isToolException|toolError(Code|Message)|tool_error_(code|message)|execution(Id|_id)|executeTool|execute_tool|actions\.execute|tools\.execute|refresh|retry' \
  src/content/docs/agentkit src/components/templates/agent-connectors \
  -g '*.mdx' -g '*.md' | head -n 500

printf '%s\n' '--- external example files ---'
examples_dir="$(mktemp -d)"
trap 'rm -rf "$examples_dir"' EXIT
git clone --depth=1 https://github.com/scalekit-developers/agent-auth-examples.git "$examples_dir" >/dev/null
find "$examples_dir" -maxdepth 4 -type f | sort | sed -n '1,220p'

printf '%s\n' '--- focused external calls ---'
rg -n -C 4 \
  'executeTool|execute_tool|ScalekitTool|isToolException|toolError|tool_error|executionId|execution_id|refresh|retry' \
  "$examples_dir/javascript" "$examples_dir/python" | head -n 800

printf '%s\n' '--- package references ---'
rg -n -C 2 \
  '`@scalekit-sdk/node`|agentkit|ScalekitUnauthorizedException|ScalekitToolException' \
  package.json pnpm-lock.yaml . \
  -g 'package.json' -g 'pyproject.toml' -g 'requirements*.txt' -g 'pnpm-lock.yaml' \
  -g '!src/content/**' -g '!src/components/**' 2>/dev/null | head -n 300

Repository: scalekit-inc/developer-docs

Length of output: 50385


🏁 Script executed:

#!/bin/bash
set -euo pipefail

examples_dir="$(mktemp -d)"
work_dir="$(mktemp -d)"
trap 'rm -rf "$examples_dir" "$work_dir"' EXIT

git clone --depth=1 https://github.com/scalekit-developers/agent-auth-examples.git "$examples_dir" >/dev/null

printf '%s\n' '--- external package manifests ---'
find "$examples_dir" -maxdepth 3 -type f \( \
  -name 'package.json' -o -name 'pyproject.toml' -o -name 'requirements*.txt' \
\) -print -exec sed -n '1,180p' {} \;

printf '%s\n' '--- external exception references ---'
rg -n -C 4 \
  'ScalekitTool|ScalekitUnauthorized|isToolException|toolError|tool_error|executionId|execution_id|retry|refresh' \
  "$examples_dir" \
  -g '!*.lock' | head -n 500

printf '%s\n' '--- npm package metadata ---'
curl -fsSL https://registry.npmjs.org/@scalekit-sdk%2fnode \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print("latest:", d["dist-tags"].get("latest")); v=d["dist-tags"].get("latest"); print("tarball:", d["versions"][v]["dist"]["tarball"])'

npm_tarball="$(curl -fsSL https://registry.npmjs.org/@scalekit-sdk%2fnode \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["versions"][d["dist-tags"]["latest"]]["dist"]["tarball"])')"
curl -fsSL "$npm_tarball" -o "$work_dir/node.tgz"
mkdir "$work_dir/node"
tar -xzf "$work_dir/node.tgz" -C "$work_dir/node"
printf '%s\n' '--- npm exception and action source ---'
rg -n -C 5 \
  'ScalekitTool|ScalekitUnauthorized|isToolException|toolError|executionId|executeTool|retry|refresh' \
  "$work_dir/node" | head -n 1000

printf '%s\n' '--- PyPI package metadata candidates ---'
for package in scalekit scalekit-sdk; do
  if curl -fsSL "https://pypi.org/pypi/$package/json" -o "$work_dir/$package.json"; then
    python3 - "$work_dir/$package.json" "$package" <<'PY'
import json, sys
d=json.load(open(sys.argv[1]))
print(sys.argv[2], "latest:", d["info"]["version"])
print("tarball:", d["urls"][0]["url"])
PY
  fi
done

Repository: scalekit-inc/developer-docs

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -euo pipefail

work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT

npm_tarball="$(curl -fsSL https://registry.npmjs.org/@scalekit-sdk%2fnode \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["versions"][d["dist-tags"]["latest"]]["dist"]["tarball"])')"
curl -fsSL "$npm_tarball" -o "$work_dir/node.tgz"
mkdir "$work_dir/node"
tar -xzf "$work_dir/node.tgz" -C "$work_dir/node"

printf '%s\n' '--- Node tool signatures ---'
sed -n '55,115p' "$work_dir/node/package/lib/tools.d.ts"
sed -n '55,105p' "$work_dir/node/package/lib/actions.d.ts"

printf '%s\n' '--- Node exception declarations ---'
sed -n '1,145p' "$work_dir/node/package/lib/errors/specific-exceptions.d.ts"

printf '%s\n' '--- Node exception implementation and retry references ---'
rg -n -C 5 \
  'isToolException|isToolError|toolErrorCode|toolErrorMessage|executionId|ScalekitTool|retry|refresh|Unauthenticated|UNAUTHENTICATED' \
  "$work_dir/node/package/lib/errors" \
  "$work_dir/node/package/lib" \
  -g '*.js' -g '*.d.ts' | head -n 1000

printf '%s\n' '--- Python package metadata ---'
curl -fsSL https://pypi.org/pypi/scalekit-sdk-python/json -o "$work_dir/python.json"
python3 - "$work_dir/python.json" <<'PY'
import json, sys
d = json.load(open(sys.argv[1]))
print("version:", d["info"]["version"])
for u in d["urls"]:
    if u["packagetype"] == "sdist":
        print("sdist:", u["url"])
PY

python_url="$(python3 - "$work_dir/python.json" <<'PY'
import json, sys
d = json.load(open(sys.argv[1]))
print(next(u["url"] for u in d["urls"] if u["packagetype"] == "sdist"))
PY
)"
curl -fsSL "$python_url" -o "$work_dir/python.tar.gz"
mkdir "$work_dir/python"
tar -xzf "$work_dir/python.tar.gz" -C "$work_dir/python"

printf '%s\n' '--- Python tool and exception references ---'
rg -n -C 5 \
  'def execute_tool|ScalekitTool|ScalekitUnauthorized|tool_error_code|tool_error_message|execution_id|is_tool|retry|refresh' \
  "$work_dir/python" | head -n 1200

Repository: scalekit-inc/developer-docs

Length of output: 50384


🏁 Script executed:

#!/bin/bash
set -euo pipefail

work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT

npm_tarball="$(curl -fsSL https://registry.npmjs.org/@scalekit-sdk%2fnode \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["versions"][d["dist-tags"]["latest"]]["dist"]["tarball"])')"
curl -fsSL "$npm_tarball" -o "$work_dir/node.tgz"
mkdir "$work_dir/node"
tar -xzf "$work_dir/node.tgz" -C "$work_dir/node"
node_pkg="$work_dir/node/package"

printf '%s\n' '--- Node signatures and exception hierarchy ---'
sed -n '85,105p' "$node_pkg/lib/tools.d.ts"
sed -n '65,90p' "$node_pkg/lib/actions.d.ts"
sed -n '1,125p' "$node_pkg/lib/errors/specific-exceptions.d.ts"
rg -n -C 3 \
  'function isToolException|isToolException\(|toolErrorCode|toolErrorMessage|executionId|class ScalekitTool' \
  "$node_pkg/lib/errors" -g '*.js' -g '*.d.ts' | head -n 450

printf '%s\n' '--- Python signatures and exception hierarchy ---'
python_url="$(curl -fsSL https://pypi.org/pypi/scalekit-sdk-python/json \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(next(u["url"] for u in d["urls"] if u["packagetype"]=="sdist"))')"
curl -fsSL "$python_url" -o "$work_dir/python.tar.gz"
mkdir "$work_dir/python"
tar -xzf "$work_dir/python.tar.gz" -C "$work_dir/python"
python_root="$(find "$work_dir/python" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
rg -n -C 3 \
  'def execute_tool|class ScalekitTool|class ScalekitUnauthorized|tool_error_code|tool_error_message|execution_id|TOOL_ERROR|__authenticate_client' \
  "$python_root/scalekit/actions" "$python_root/scalekit/common/exceptions.py" \
  "$python_root/scalekit/common/core.py" "$python_root/tests/test_sk819_retry_behavior.py" \
  -g '*.py' | head -n 900

printf '%s\n' '--- gmail send tool input references ---'
rg -n -C 5 \
  'gmail_send_email|send_email|toolInput|tool_input|params:' \
  src/content/docs/agentkit "$node_pkg" \
  -g '*.mdx' -g '*.md' -g '*.js' -g '*.d.ts' -g '*.py' | head -n 700

Repository: scalekit-inc/developer-docs

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

work_dir="$(mktemp -d)"
examples_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir" "$examples_dir"' EXIT

python_url="$(curl -fsSL https://pypi.org/pypi/scalekit-sdk-python/json \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(next(u["url"] for u in d["urls"] if u["packagetype"]=="sdist"))')"
curl -fsSL "$python_url" -o "$work_dir/python.tar.gz"
mkdir "$work_dir/python"
tar -xzf "$work_dir/python.tar.gz" -C "$work_dir/python"
python_root="$(find "$work_dir/python" -mindepth 1 -maxdepth 1 -type d | head -n 1)"

printf '%s\n' '--- Python execute_tool signature and client exposure ---'
sed -n '105,145p' "$python_root/scalekit/actions/actions.py"
rg -n -C 3 \
  'class .*Tools|def execute_tool|self\.tools|tools =' \
  "$python_root/scalekit" -g '*.py' | head -n 350

printf '%s\n' '--- Gmail send references in repository ---'
rg -n -C 6 \
  'gmail_send_email|send_email' \
  src/content/docs/agentkit src/components/templates/agent-connectors \
  -g '*.mdx' -g '*.md' | head -n 500 || true

printf '%s\n' '--- Gmail send references in current external examples ---'
git clone --depth=1 https://github.com/scalekit-developers/agent-auth-examples.git "$examples_dir" >/dev/null
rg -n -C 6 \
  'gmail_send_email|send_email' \
  "$examples_dir" | head -n 500 || true

printf '%s\n' '--- reviewed code fence attributes ---'
rg -n \
  '^```(ts|typescript|python)( |$)' \
  src/content/docs/agentkit/sdks/node/errors.mdx \
  src/content/docs/agentkit/sdks/python/errors.mdx

Repository: scalekit-inc/developer-docs

Length of output: 32221


🏁 Script executed:

#!/bin/bash
set -euo pipefail

work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT

python_url="$(curl -fsSL https://pypi.org/pypi/scalekit-sdk-python/json \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(next(u["url"] for u in d["urls"] if u["packagetype"]=="sdist"))')"
curl -fsSL "$python_url" -o "$work_dir/python.tar.gz"
mkdir "$work_dir/python"
tar -xzf "$work_dir/python.tar.gz" -C "$work_dir/python"
python_root="$(find "$work_dir/python" -mindepth 1 -maxdepth 1 -type d | head -n 1)"

printf '%s\n' '--- Python tools.execute_tool signature ---'
sed -n '88,135p' "$python_root/scalekit/tools.py"

printf '%s\n' '--- Python tools request construction ---'
sed -n '135,190p' "$python_root/scalekit/tools.py"

printf '%s\n' '--- Gmail input examples in documentation ---'
sed -n '88,103p' src/content/docs/agentkit/authentication/token-management.mdx
sed -n '324,334p' src/content/docs/agentkit/authentication/token-management.mdx

Repository: scalekit-inc/developer-docs

Length of output: 2676


Make both error examples runnable and preserve full diagnostics.

  • Pass to, subject, and body through params for gmail_send_email.
  • Log toolErrorMessage with the other diagnostic fields.
  • Add title attributes to both fenced code blocks.
📍 Affects 2 files
  • src/content/docs/agentkit/sdks/node/errors.mdx#L60-L101 (this comment)
  • src/content/docs/agentkit/sdks/python/errors.mdx#L58-L97
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/content/docs/agentkit/sdks/node/errors.mdx` around lines 60 - 101, Update
both error examples in src/content/docs/agentkit/sdks/node/errors.mdx (lines
60-101) and src/content/docs/agentkit/sdks/python/errors.mdx (lines 58-97): make
each gmail_send_email call runnable by passing to, subject, and body through
params, add title attributes to both fenced code blocks, and include
toolErrorMessage alongside the existing diagnostic fields in logging. Ensure the
corresponding language-specific syntax remains valid.

Source: Path instructions


## Related

- [Connected accounts](/agentkit/sdks/node/actions/) — connect accounts and execute tools
Expand Down
43 changes: 43 additions & 0 deletions src/content/docs/agentkit/sdks/python/errors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,49 @@ except ScalekitServerException as e:

`ScalekitServerException` is the base type. Prefer checking subclasses first so not-found and auth failures get the right UX.

## Tool execution errors

A failure during `scalekit_client.tools.execute_tool` comes from one of two places, and the fix differs for each:

- **The upstream provider rejected the call** (Gmail, Slack, Salesforce, and so on). Scalekit raises a dedicated `ScalekitTool*` exception. The most common is `ScalekitToolUnauthorizedException`, which means the connected account's provider token was expired or revoked — re-authorize the connected account. Do not change your client credentials.
- **Scalekit rejected the call.** A plain `ScalekitUnauthorizedException` (no tool details) means your `client_id`/`client_secret` or Scalekit token is invalid. The SDK already refreshed and retried before surfacing it, so fix the credentials.

Each tool exception subclasses both `ScalekitToolException` and its plain counterpart — `ScalekitToolUnauthorizedException` extends `ScalekitUnauthorizedException` — so **catch the tool type first**. Catch the `ScalekitToolException` base to handle any upstream tool failure, and read `tool_error_code`, `tool_error_message`, and `execution_id` for logging.

```python wrap showLineNumbers=false
from scalekit.common.exceptions import (
ScalekitToolUnauthorizedException,
ScalekitToolRateLimitException,
ScalekitUnauthorizedException,
ScalekitToolException,
)

try:
result = scalekit_client.tools.execute_tool(
tool_name="gmail_send_email",
identifier="user@example.com",
)
except ScalekitToolUnauthorizedException:
# Upstream provider rejected the token — re-authorize the connected account
pass
except ScalekitToolRateLimitException:
# Upstream provider rate limit — back off, then retry the tool call
pass
except ScalekitUnauthorizedException:
# Scalekit-side credentials are invalid — fix client ID/secret
pass
except ScalekitToolException as e:
# Any other upstream tool failure — inspect the provider's error code
print(e.tool_error_code, e.execution_id)
```

| Exception | When it is raised | Typical response |
| --- | --- | --- |
| `ScalekitToolUnauthorizedException` | Upstream provider returned 401 during tool execution | Re-authorize the connected account |
| `ScalekitToolForbiddenException` | Upstream provider returned 403 during tool execution | Add the missing provider scope, then re-authorize |
| `ScalekitToolRateLimitException` | Upstream provider returned 429 during tool execution | Back off and retry the tool call |
| `ScalekitToolException` | Base class for any upstream provider error during tool execution | Log `tool_error_code` and `execution_id`; surface a clear message |

## Related

- [Connected accounts](/agentkit/sdks/python/actions/) — connect accounts and execute tools
Expand Down