Skip to content
Back to skills

2077 Gotchas 8298b63f

ASecurity

**Problem:** "stream already consumed" or worker hangs

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 11, 2026
code-qualitytypescriptrustgobashdebugginggit

Works with

  • cli

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2077-gotchas_8298b63f --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2077 Gotchas 8298b63f?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2077 Gotchas 8298b63f
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2077-gotchas-8298b63f/badge)](https://www.skillsdirectory.com/skills/tools-only-2077-gotchas-8298b63f)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Gotchas & Troubleshooting

## Critical Pitfalls

### Stream Consumption (MOST COMMON)

**Problem:** "stream already consumed" or worker hangs

**Cause:** `message.raw` is `ReadableStream` - consume once only

**Solution:**
```typescript
// ❌ WRONG
const email1 = await parser.parse(await message.raw.arrayBuffer());
const email2 = await parser.parse(await message.raw.arrayBuffer()); // FAILS

// ✅ CORRECT
const raw = await message.raw.arrayBuffer();
const email = await parser.parse(raw);
```

Consume `message.raw` immediately before any async operations.

### Destination Verification

**Problem:** Emails not forwarding

**Cause:** Destination unverified

**Solution:** Add destination, check inbox for verification email, click link. Verify status: `GET /zones/{id}/email/routing/addresses`

### Mail Authentication

**Problem:** Legitimate emails rejected

**Cause:** Missing SPF/DKIM/DMARC on sender domain

**Solution:** Configure sender DNS:
```dns
example.com. IN TXT "v=spf1 include:_spf.example.com ~all"
selector._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=..."
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine"
```

### Envelope vs Header

**Problem:** Filtering on wrong address

**Solution:**
```typescript
// Routing/auth: envelope
if (message.from === "trusted@example.com") { }

// Display: headers
const display = message.headers.get("from");
```

### SendEmail Limits

| Issue | Limit | Solution |
|-------|-------|----------|
| From domain | Must own | Use Email Routing domain |
| Volume | ~100/min Free | Upgrade or throttle |
| Attachments | Not supported | Link to R2 |
| Type | Transactional | No bulk |

## Common Errors

### CPU Time Exceeded

**Cause:** Heavy parsing, large emails

**Solution:**
```typescript
const size = parseInt(message.headers.get("content-length") || "0") / 1024 / 1024;
if (size > 20) {
  message.setReject("Too large");
  return;
}

ctx.waitUntil(expensiveWork());
await message.forward("dest@example.com");
```

### Rule Not Triggering

**Causes:** Priority conflict, matcher error, catch-all override

**Solution:** Check priority (lower=first), verify exact match, confirm destination verified

### Undefined Property

**Cause:** Missing header

**Solution:**
```typescript
// ❌ WRONG
const subj = message.headers.get("subject").toLowerCase();

// ✅ CORRECT
const subj = message.headers.get("subject")?.toLowerCase() || "";
```

## Limits

| Resource | Free | Paid |
|----------|------|------|
| Email size | 25 MB | 25 MB |
| Rules | 200 | 200 |
| Destinations | 200 | 200 |
| CPU time | 10ms | 50ms |
| SendEmail | ~100/min | Higher |

## Debugging

### Local

```bash
npx wrangler dev

curl -X POST 'http://localhost:8787/__email' \
  --header 'content-type: message/rfc822' \
  --data 'From: test@example.com
To: you@yourdomain.com
Subject: Test

Body'
```

### Production

```bash
npx wrangler tail
```

### Pattern

```typescript
export default {
  async email(message, env, ctx) {
    try {
      console.log("From:", message.from);
      await process(message, env);
    } catch (err) {
      console.error(err);
      message.setReject(err.message);
    }
  }
} satisfies ExportedHandler;
```

## Auth Troubleshooting

### Check Status

```typescript
const auth = message.headers.get("authentication-results") || "";
console.log({
  spf: auth.includes("spf=pass"),
  dkim: auth.includes("dkim=pass"),
  dmarc: auth.includes("dmarc=pass")
});

if (!auth.includes("pass")) {
  message.setReject("Failed auth");
  return;
}
```

### SPF Issues

**Causes:** Forwarding breaks SPF, too many lookups (>10), missing includes

**Solution:**
```dns
; ✅ Good
example.com. IN TXT "v=spf1 include:_spf.google.com ~all"

; ❌ Bad - too many
example.com. IN TXT "v=spf1 include:a.com include:b.com ... ~all"
```

### DMARC Alignment

**Cause:** From domain must match SPF/DKIM domain

## Best Practices

1. Consume `message.raw` immediately
2. Verify destinations
3. Handle missing headers (`?.`)
4. Use envelope for routing
5. Check spam scores
6. Test locally first
7. Use `ctx.waitUntil` for background work
8. Size-check early

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.