# Handling Undefined Response Types in AWS SDK v3 with TypeScript

> Master AWS SDK v3 with TypeScript: learn to handle undefined response types and prevent runtime errors using strict null checks and defensive programming.

- Repository: [Amazon Web Services/agent-toolkit-for-aws](https://github.com/aws/agent-toolkit-for-aws)
- Tags: handling-errors
- Published: 2026-06-29

---

**AWS SDK v3 returns response objects with optional properties typed as `T | undefined`, requiring strict null checks and defensive programming to prevent runtime errors when accessing potentially missing fields.**

AWS SDK v3 is fully modular, shipping as individual client packages like `@aws-sdk/client-s3` where response fields are omitted when empty. When developing with the `aws/agent-toolkit-for-aws` repository, which compiles TypeScript with strict null checks enabled in the `skills/` folder, you must handle these potentially undefined values to avoid runtime exceptions like `Cannot read property of undefined`.

## Why SDK v3 Uses Optional Types

Unlike previous SDK versions, AWS SDK v3 generates TypeScript definitions that mark response properties as optional when the AWS API may omit them. For example, `S3Client` returns `GetObjectOutput` where `Body?: ReadableStream | Uint8Array | Blob | string`. This design accurately reflects service behavior but requires developers to verify field existence before accessing nested properties or calling methods.

## Enable Strict Null Checks

The `aws/agent-toolkit-for-aws` repository enforces **strict type-checking** across its skill modules. Configure your [`tsconfig.json`](https://github.com/aws/agent-toolkit-for-aws/blob/main/tsconfig.json) to catch undefined errors at compile time:

```typescript
{
  "compilerOptions": {
    "strict": true,
    // or specifically:
    "strictNullChecks": true
  }
}

```

This configuration, as implemented in the `skills/` folder of the repository, forces TypeScript to treat `undefined` as a distinct type that must be explicitly narrowed or guarded.

## Guard Against Undefined Values

Always verify optional properties exist before using them. The following pattern demonstrates safe handling of the optional `Body` property in S3 `GetObject` responses:

```typescript
import { S3Client, GetObjectCommand, GetObjectOutput } from "@aws-sdk/client-s3";

export async function getObjectText(bucket: string, key: string): Promise<string> {
  const client = new S3Client({ region: "us-east-1" });
  const output: GetObjectOutput = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));

  // Guard against a missing body
  if (!output.Body) {
    throw new Error(`Object ${key} in bucket ${bucket} has no body`);
  }

  // Convert the readable stream to a string
  const stream = output.Body as ReadableStream;
  const chunks: Uint8Array[] = [];
  const reader = stream.getReader();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    if (value) chunks.push(value);
  }

  const decoder = new TextDecoder("utf-8");
  return decoder.decode(Buffer.concat(chunks));
}

```

## Type Predicates for Narrowing

Create reusable type guards to narrow types safely. The `hasProp` helper checks if a property is defined and narrows the TypeScript type accordingly:

```typescript
/**
 * Generic guard that checks a property is not undefined.
 * Usage: if (hasProp(resp, 'Body')) { … }
 */
export function hasProp<T, K extends keyof T>(obj: T, prop: K): obj is T & Record<K, NonNullable<T[K]>> {
  return obj[prop] !== undefined;
}

// Example usage with SDK responses
if (hasProp(output, "Body")) {
  // `output.Body` is now known to be defined
  const stream = output.Body;
}

```

## Safe Pagination Handling

Paginated operations like `ListObjectsV2Command` may return `undefined` for page contents. Use the **nullish coalescing operator** to provide safe defaults:

```typescript
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";

export async function listAllKeys(bucket: string): Promise<string[]> {
  const client = new S3Client({ region: "us-east-1" });
  const keys: string[] = [];

  for await (const page of paginateListObjectsV2({ client }, { Bucket: bucket })) {
    // `Contents` may be undefined – default to an empty array
    const objects = page.Contents ?? [];

    for (const obj of objects) {
      if (obj.Key) keys.push(obj.Key);
    }
  }

  return keys;
}

```

## Repository Context and File Locations

These patterns align with the **Agent Toolkit for AWS** architecture, where skills invoking AWS services follow strict TypeScript configurations. Key files demonstrating this integration include:

- **[`README.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/README.md)** – Provides the overall repository overview and packaging context for agent skills
- **[`plugins/aws-core/skills/aws-serverless/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-core/skills/aws-serverless/SKILL.md)** – Describes how TypeScript modules import and execute AWS SDK clients within serverless skills
- **[`skills/core-skills/aws-serverless/references/lambda.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-serverless/references/lambda.md)** – Contains examples of invoking AWS services from Lambda execution environments
- **[`plugins/aws-core/skills/aws-sdk-swift-usage/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-core/skills/aws-sdk-swift-usage/SKILL.md)** – Demonstrates the modular client pattern that mirrors the TypeScript SDK architecture
- **[`plugins/aws-data-analytics/skills/storing-and-querying-vectors/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-data-analytics/skills/storing-and-querying-vectors/SKILL.md)** – Shows data service implementations where SDK clients handle optional response fields

## Summary

- **Enable strict null checks** in [`tsconfig.json`](https://github.com/aws/agent-toolkit-for-aws/blob/main/tsconfig.json) to catch undefined errors at compile time
- **Guard every optional property** before accessing nested values, particularly with `GetObjectOutput.Body`
- **Use type predicates** like `hasProp` to narrow types and satisfy TypeScript's control-flow analysis
- **Apply nullish coalescing** (`??`) to paginated results to ensure arrays are always defined
- **Reference the repository's `skills/` folder** structure when implementing SDK calls in Agent Toolkit skills

## Frequently Asked Questions

### How do I handle the `Body` property in S3 GetObject responses?

The `Body` property in `GetObjectOutput` is typed as `ReadableStream | Uint8Array | Blob | string | undefined`. Always check `if (!output.Body)` before streaming, or use a type guard function to narrow the type. Attempting to access `Body` without checking results in a compile-time error under strict null checks or a runtime `Cannot read property of undefined` error.

### Why does AWS SDK v3 mark response fields as optional?

AWS SDK v3 reflects the actual AWS API behavior where services omit fields that have no value rather than returning null. This modular approach generates TypeScript definitions with `property?: T` syntax, making `undefined` a valid state that developers must explicitly handle before accessing properties.

### What is the best way to handle paginated responses that might be empty?

Use the nullish coalescing operator (`??`) to provide default empty arrays for optional paginated lists. For example, when using `paginateListObjectsV2`, write `const objects = page.Contents ?? []` to ensure your iteration logic never receives undefined, as shown in the [`skills/core-skills/aws-serverless/references/lambda.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-serverless/references/lambda.md) patterns.

### Where can I find examples of TypeScript SDK usage in the Agent Toolkit?

The `aws/agent-toolkit-for-aws` repository contains relevant examples in [`plugins/aws-core/skills/aws-serverless/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-core/skills/aws-serverless/SKILL.md) and [`skills/core-skills/aws-serverless/references/lambda.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-serverless/references/lambda.md). These files demonstrate how SDK clients are instantiated and used within the toolkit's skill architecture, following the strict TypeScript configuration defined in the `skills/` folder.