{"record":{"id":"0f4ae72abf272805","repo":"anomalyco/sst","slug":"failed-to-stop-task","errorCode":null,"errorMessage":"Failed to stop task","messagePattern":"Failed to stop task","errorType":"error_code","errorClass":"StopError","httpStatus":null,"severity":"error","filePath":"sdk/js/src/aws/task.ts","lineNumber":330,"sourceCode":"   * [`StopTask`](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_StopTask.html).\n   */\n  export async function stop(\n    resource: Resource,\n    task: string,\n    options?: Options\n  ): Promise<StopResponse> {\n    const res = await awsFetch(\"ecs\", \"/\", {\n      method: \"POST\",\n      headers: {\n        \"X-Amz-Target\": \"AmazonEC2ContainerServiceV20141113.StopTask\",\n        \"Content-Type\": \"application/x-amz-json-1.1\",\n      },\n      body: JSON.stringify({\n        cluster: resource.cluster,\n        task,\n      }),\n    }, options);\n    if (!res.ok) throw new StopError(res);\n\n    const data = (await res.json()) as {\n      task: {\n        taskArn: string;\n        lastStatus: string;\n      };\n    };\n    if (!data.task) throw new StopError(res);\n\n    return {\n      arn: data.task.taskArn,\n      status: data.task.lastStatus,\n      response: data,\n    };\n  }\n\n  export class DescribeError extends Error {\n    constructor(public readonly response: Response) {","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/sdk/js/src/aws/task.ts#L312-L348","documentation":"`task.stop` calls the ECS StopTask API via awsFetch. If the HTTP response is not OK, a `StopError` with message \"Failed to stop task\" is thrown; the raw `Response` is attached as `error.response` so the AWS error body can be examined (e.g. AccessDeniedException, invalid ARN).","triggerScenarios":"Calling `task.stop(resource, taskArn)` where the ECS StopTask request returns non-OK: missing IAM `ecs:StopTask` permission, task ARN not found or already stopped, wrong cluster, or malformed ARN.","commonSituations":"Function's IAM role lacks ecs:StopTask; stopping a task that already completed/stopped (StopTask returns Missing/Invalid ARN); passing a truncated ARN; stopping a task in a different cluster than the linked resource.","solutions":["Read `error.response` body for the exact AWS error code.","Grant the caller's IAM role `ecs:StopTask` on the cluster.","Check the task's current state with `task.describe` first — if already stopped, skip the stop call.","Verify the ARN is complete and belongs to `resource.cluster`."],"exampleFix":"const current = await task.describe(Resource.MyTask, arn);\nif (current.status !== \"STOPPED\") {\n  await task.stop(Resource.MyTask, arn);\n}","handlingStrategy":"try-catch","validationCode":"const status = await task.describe(Resource.MyTask, arn).catch(() => null);\nif (!status || status.status === \"STOPPED\") return; // nothing to stop","typeGuard":"function isStopError(e: unknown): e is task.StopError {\n  return e instanceof task.StopError && typeof e.response === \"object\";\n}","tryCatchPattern":"try {\n  await task.stop(Resource.MyTask, arn);\n} catch (e) {\n  if (isStopError(e)) {\n    const detail = await e.response.text();\n    if (detail.includes(\"MISSING\") || detail.includes(\"not found\")) return; // already stopped\n    throw e;\n  }\n  throw e;\n}","preventionTips":["Check task status with describe before stopping to avoid not-found errors.","Link the task resource so ecs:StopTask IAM permission is granted.","Remember stop is asynchronous — poll describe for STOPPED rather than assuming immediate termination."],"tags":["aws","ecs","network","iam"],"backgroundTag":"aws-api-request-failed","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}