TL;DR You forgot a second await. Body reading methods like .text() and .json() are async. Always await them.
The Bug in One Line

const text = response.text(); // Returns a Promise, not text
How to Spot It at a Glance
If you console.log() a value and see any of the following, a missing await is almost always the culprit:
Promise {<pending>}
Promise {<fulfilled>: undefined}
[object Promise]
Key Takeaway
fetch() gives you a Response. .text() and .json() give you the body but only after a second await.
Two async steps. Two awaits. Every time.
What Actually Happen
When you fetch() a URL, JavaScript resolves the request in two stages:
- The HTTP response headers arrive →
await fetch(url)resolves. - The response body streams in →
await response.text()resolves.
Most developers await stage 1 but forget stage 2. The result? You’re holding a Promise {<pending>} object and wondering why your string looks like an object.
The Fix
// Before - missing the second await
const response = await fetch('https://api.example.com/data');
const text = response.text();
console.log(text); // Promise {<pending>}
// After - both stages awaited
const response = await fetch('https://api.example.com/data');
const text = await response.text();
console.log(text); // "Hello, world!"
It Affect All Body Methods
This isn’t just a .text() problem. Every body-reading method on a Response object is async:
| Method | Returns |
|---|---|
response.text() | Promise<string> |
response.json() | Promise<any> |
response.blob() | Promise<Blob> |
response.arrayBuffer() | Promise<ArrayBuffer> |
response.formData() | Promise<FormData> |
Rule of thumb: If it’s on a Response object, it needs an await.
Valid Pattern
// Pattern 1: Two lines, two awaits (most readable)
const response = await fetch(url);
const data = await response.json();
// Pattern 2: One-liner (compact, slightly harder to debug)
const data = await (await fetch(url)).json();
// Pattern 3: Error handling with try/catch (production-ready)
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
const data = await response.json();
console.log(data);
} catch (err) {
console.error('Fetch failed:', err);
}
How to Spot This Bug Fast
If you ever console.log() a value and see any of these, a missing await is almost always the culprit:
Promise {<pending>}.Promise {<fulfilled>: undefined}.[object Promise].
Tools to Catch This Bug Early
Don’t wait until runtime to discover a missing await. These tools will flag it instantly:
| Tool | How it helps |
|---|---|
| VS Code | Yellow squiggly underline on un-awaited Promises |
| ESLint | no-floating-promises rule catches it at lint time |
| TypeScript | Strict mode throws a type error Promise<string> ≠ string |
| Chrome / Firefox DevTools | Console prints Promise {<pending>} the clearest visual clue |
| Vitest / Jest | Async tests fail when you accidentally assert a Promise object |
| Prettier | Consistent formatting makes missing awaits easier to spot visually |
Fastest setup: Enable TypeScript strict mode + ESLint together they catch this error before you even run the code.