The updateTaskStatus method reports the outcome of one taskRunner invocation back to the
platform. Call it before returning from your handler. The platform uses this to surface task
health in the connector UI and to decide whether to retry the task.
For failures, choose the failureReason that best describes the cause. The platform may treat
different reasons differently: authentication-related reasons typically surface as
admin-actionable errors in the connector UI, while retryable reasons trigger silent retries.
1 2updateTaskStatus(request: TaskStatusUpdateRequest): Promise<TaskStatusUpdateResponse>
TaskStatusUpdateRequest1 2{ scanId: string; // From the current TaskRunnerPayload taskExecutionId: string; // From the current TaskRunnerPayload status: 'success' | 'failure'; task: TaskStatusUpdateTask; failureReason?: FailureReason; // Required when status is 'failure' connectionId: string; // From the current TaskRunnerPayload }
TaskStatusUpdateTask1 2{ taskId: string; // From the current TaskRunnerPayload }
failureReason valuesfailureReason | When to use |
|---|---|
ENTITY_NOT_FOUND | The work item itself disappeared at the source (for example, a 404 fetching the file your task was meant to ingest). |
RETRY_LIMIT_EXCEEDED | Your code's own retry counter is exhausted and you no longer want the platform to retry. |
NON_RETRYABLE_ERROR | A permanent failure such as bad configuration or a malformed payload. The platform skips retries. |
UNAUTHORIZED | The caller lacks permission to perform the operation at the source. |
AUTH_TOKEN_REVOKED | The auth token was revoked at the source. |
AUTH_TOKEN_EXPIRED | The auth token TTL has elapsed and a refresh failed. |
RATE_LIMITED | The upstream service rate-limited the request. |
RETRYABLE_ERROR | A transient failure where retrying may succeed (default for unknown errors). |
The retry and escalation behavior is decided by the platform based on the failureReason you
submit. The connector's responsibility is to pick the value that best describes what went
wrong; use the description column in the table above as your guide.
1 2import { graph } from '@forge/teamwork-graph'; export async function taskRunner(request: TaskRunnerPayload) { await doTheWork(request); await graph.updateTaskStatus({ scanId: request.scanId, taskExecutionId: request.taskExecutionId, connectionId: request.connectionId, status: 'success', task: { taskId: request.taskId }, }); return { success: true }; }
1 2import { graph, types } from '@forge/teamwork-graph'; export async function taskRunner(request: TaskRunnerPayload) { try { await doTheWork(request); await graph.updateTaskStatus({ scanId: request.scanId, taskExecutionId: request.taskExecutionId, connectionId: request.connectionId, status: 'success', task: { taskId: request.taskId }, }); return { success: true }; } catch (error) { await graph.updateTaskStatus({ scanId: request.scanId, taskExecutionId: request.taskExecutionId, connectionId: request.connectionId, status: 'failure', failureReason: classify(error), task: { taskId: request.taskId }, }); return { success: false, message: String(error) }; } } function classify(error: unknown): types.TaskStatusUpdateRequest['failureReason'] { if (isHttp(error, 401)) return 'UNAUTHORIZED'; if (isHttp(error, 403)) return 'UNAUTHORIZED'; if (isHttp(error, 404)) return 'ENTITY_NOT_FOUND'; if (isHttp(error, 429)) return 'RATE_LIMITED'; return 'RETRYABLE_ERROR'; }
Always call updateTaskStatus before returning from taskRunner. Returning without it leaves
the task's status undefined from the platform's perspective. failureReason is ignored when
status is 'success'; set it only on the failure path.
Duplicate deliveries of the same (taskId, scanId) carry a fresh taskExecutionId. If the
original execution already reported success, calling updateTaskStatus({ status: 'failure' })
from a duplicate overwrites that success. Short-circuit duplicate invocations to a no-op success
instead. See
At-least-once delivery and idempotency.
The method validates the following:
connectionId: Required, must be a non-empty string.status: Must be exactly 'success' or 'failure'.task.taskId: Required, must be a valid UUID.failureReason: When provided, must be one of the eight values listed above.The scanId and taskExecutionId fields are not validated client-side; pass them through
unchanged from the current TaskRunnerPayload.
| Error message | Description |
|---|---|
connectionId is required | The connectionId is missing or empty. |
status must be one of: success, failure | The status field is missing or not one of the allowed values. |
task.taskId is required | The task.taskId is missing. Pass request.taskId from the current TaskRunnerPayload. |
task.taskId must be a valid UUID format | The provided taskId is not a valid UUID. |
failureReason must be one of: ENTITY_NOT_FOUND, RETRY_LIMIT_EXCEEDED, ... | The failureReason is not one of the supported values. See the table above. |
The method returns a promise that resolves to a TaskStatusUpdateResponse.
1 2{ status: string; // Status string from the platform (e.g. "ACCEPTED") message: string; // Human-readable status message error?: string; // Error message if the request failed originalError?: unknown; // Original platform error object, when available }
On success, the response carries status and message. On failure, the SDK returns an object
with error and originalError populated. Branch on response.error to detect failures.
The SDK provides type-safe request and response objects that ensure compile-time validation:
1 2import { graph, types } from '@forge/teamwork-graph'; const request: types.TaskStatusUpdateRequest = { scanId: incomingPayload.scanId, taskExecutionId: incomingPayload.taskExecutionId, connectionId: incomingPayload.connectionId, status: 'failure', failureReason: 'RATE_LIMITED', task: { taskId: incomingPayload.taskId }, }; const response: types.TaskStatusUpdateResponse = await graph.updateTaskStatus(request); if (response.error) { console.error('Failed to update task status:', response.error); }
The type system ensures:
status is restricted to 'success' | 'failure'.failureReason is constrained to the eight supported values.request has the correct TaskStatusUpdateRequest structure.response is properly typed as TaskStatusUpdateResponse with optional error and
originalError.Rate this page: