Latest Updated Pages
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
Deploy to Production / Build & Verify (push) Failing after 13s
Ping Search Engines / Notify Search Engines (push) Successful in 3s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 1s
E2E Test Suite / Smoke Tests (P0) (push) Failing after 9m36s
E2E Test Suite / Form Interaction Tests (push) Failing after 12m6s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 11m46s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 9m31s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 11m5s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 15m24s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 6s
E2E Test Suite / Mobile Device Tests (push) Failing after 3h12m28s
Uptime Monitor / Health & Response Time (push) Successful in 5s
Uptime Monitor / SSL Certificate (push) Successful in 3s
Uptime Monitor / Send Alerts (push) Has been skipped
Uptime Monitor / Record Uptime Success (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
Deploy to Production / Build & Verify (push) Failing after 13s
Ping Search Engines / Notify Search Engines (push) Successful in 3s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 1s
E2E Test Suite / Smoke Tests (P0) (push) Failing after 9m36s
E2E Test Suite / Form Interaction Tests (push) Failing after 12m6s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 11m46s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 9m31s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 11m5s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 15m24s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 6s
E2E Test Suite / Mobile Device Tests (push) Failing after 3h12m28s
Uptime Monitor / Health & Response Time (push) Successful in 5s
Uptime Monitor / SSL Certificate (push) Successful in 3s
Uptime Monitor / Send Alerts (push) Has been skipped
Uptime Monitor / Record Uptime Success (push) Successful in 2s
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
# Blog 500 Error — Debug Report
|
||||
|
||||
**Agent**: backend-specialist
|
||||
**Date**: 2026-03-21
|
||||
**Priority**: High
|
||||
**Status**: RESOLVED
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Individual blog post pages (`/blog/<slug>`) returned a **500 Internal Server Error** because `src/pages/blog/[...slug].astro` used `getStaticPaths()` — a Static Site Generation (SSG) API that is **not valid in SSR (`output: 'server'`) mode**.
|
||||
|
||||
---
|
||||
|
||||
## Root Cause
|
||||
|
||||
### The Conflict
|
||||
|
||||
| File | Setting |
|
||||
|------|---------|
|
||||
| `astro.config.mjs` | `output: 'server'` (full SSR, Node adapter) |
|
||||
| `src/pages/blog/[...slug].astro` | Used `getStaticPaths()` (SSG-only API) |
|
||||
|
||||
**Astro's `getStaticPaths()` is only valid in `output: 'static'` mode.** When the server receives a request for `/blog/getting-started-with-astro`, Astro attempts to call `getStaticPaths()` at request time, which is unsupported and causes a runtime error propagated as a 500.
|
||||
|
||||
### Error Flow
|
||||
|
||||
```
|
||||
GET /blog/getting-started-with-astro
|
||||
→ Astro SSR handler invokes [...slug].astro
|
||||
→ getStaticPaths() is called at request time
|
||||
→ Astro throws: "getStaticPaths() is not available in server mode"
|
||||
→ middleware.ts catches and re-throws (line 73)
|
||||
→ 500 Internal Server Error returned to client
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files Examined
|
||||
|
||||
| File | Finding |
|
||||
|------|---------|
|
||||
| `astro.config.mjs` | `output: 'server'` with `@astrojs/node` standalone adapter |
|
||||
| `src/pages/blog/[...slug].astro` | Used `getStaticPaths()` — incompatible with SSR |
|
||||
| `src/pages/blog/index.astro` | Correctly uses `getCollection()` at the top level (valid in SSR) |
|
||||
| `src/content/config.ts` | Schema is valid; `blog` collection properly defined |
|
||||
| `src/content/blog/*.md` | All 3 posts have valid frontmatter matching the schema |
|
||||
| `src/middleware.ts` | Re-throws errors from `next()` — confirms 500 path |
|
||||
|
||||
---
|
||||
|
||||
## Fix Applied
|
||||
|
||||
**File**: `src/pages/blog/[...slug].astro`
|
||||
|
||||
### Before (broken SSG pattern)
|
||||
```typescript
|
||||
import { getCollection, type CollectionEntry } from 'astro:content';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('blog', ({ data }) => !data.draft);
|
||||
return posts.map((post) => ({
|
||||
params: { slug: post.slug },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
|
||||
type Props = { post: CollectionEntry<'blog'> };
|
||||
const { post } = Astro.props;
|
||||
const { Content } = await post.render();
|
||||
```
|
||||
|
||||
### After (correct SSR pattern)
|
||||
```typescript
|
||||
import { getEntry } from 'astro:content';
|
||||
|
||||
const { slug } = Astro.params;
|
||||
|
||||
if (!slug) {
|
||||
return Astro.redirect('/blog');
|
||||
}
|
||||
|
||||
const post = await getEntry('blog', slug);
|
||||
|
||||
if (!post || post.data.draft) {
|
||||
return Astro.redirect('/404');
|
||||
}
|
||||
|
||||
const { Content } = await post.render();
|
||||
```
|
||||
|
||||
### Key Changes
|
||||
- Removed `getStaticPaths()` entirely
|
||||
- Replaced `getCollection` import with `getEntry`
|
||||
- Reads `slug` dynamically from `Astro.params` at request time
|
||||
- Handles missing/draft posts with a redirect to `/404`
|
||||
- No `Props` type annotation needed (props come from params now)
|
||||
|
||||
---
|
||||
|
||||
## Why `getEntry()` is the Correct SSR Approach
|
||||
|
||||
In SSR mode, Astro dynamically serves each request. The URL slug is available at runtime via `Astro.params`. `getEntry('blog', slug)` fetches a single content collection entry by its slug — this is the official Astro SSR pattern for content collections.
|
||||
|
||||
---
|
||||
|
||||
## Secondary Observations
|
||||
|
||||
These are not the cause of the 500 but are worth noting:
|
||||
|
||||
1. **`index.astro` works fine** — it uses `getCollection()` directly in the frontmatter (not in `getStaticPaths()`), which is valid in SSR since it runs per-request.
|
||||
|
||||
2. **Content is valid** — all 3 markdown posts pass the Zod schema in `config.ts`. No frontmatter issues.
|
||||
|
||||
3. **Middleware correctly re-throws** — the error handling in `middleware.ts` was functioning as designed; the 500 originated from the page handler, not the middleware itself.
|
||||
|
||||
4. **Blog index not affected** — `/blog` (list page) was working correctly; only individual post routes were broken.
|
||||
|
||||
---
|
||||
|
||||
## Testing the Fix
|
||||
|
||||
After deploying, verify the following URLs return 200:
|
||||
|
||||
```
|
||||
GET /blog/getting-started-with-astro → 200 OK
|
||||
GET /blog/ai-transforming-business → 200 OK
|
||||
GET /blog/cloud-migration-guide → 200 OK
|
||||
GET /blog/nonexistent-slug → redirect to /404
|
||||
```
|
||||
@@ -5,7 +5,7 @@ status: idle
|
||||
health: healthy
|
||||
current_task: none
|
||||
current_task_id: none
|
||||
last_active: 2026-03-21T09:44:14.387868+00:00
|
||||
last_active: 2026-03-21T13:39:41.964494+00:00
|
||||
iterations_completed: 0
|
||||
---
|
||||
|
||||
@@ -13,7 +13,7 @@ iterations_completed: 0
|
||||
|
||||
**Status**: IDLE
|
||||
**Health**: healthy
|
||||
**Last Active**: 2026-03-21 09:44:14 UTC
|
||||
**Last Active**: 2026-03-21 13:39:41 UTC
|
||||
|
||||
## Current Task
|
||||
_No active task_
|
||||
@@ -21,5 +21,5 @@ _No active task_
|
||||
## Activity Log
|
||||
| Time | Event |
|
||||
|------|-------|
|
||||
| 09:44:14 | Heartbeat recorded — idle |
|
||||
| 13:39:41 | Heartbeat recorded — idle |
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
agent_id: a28de37e-1a69-48d0-8224-13a1d5bf646e
|
||||
name: backend-specialist
|
||||
role: backend-specialist
|
||||
created: 2026-03-21T09:39:28.084682+00:00
|
||||
created: 2026-03-21T13:37:45.325197+00:00
|
||||
---
|
||||
|
||||
# backend-specialist
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
role: backend-specialist
|
||||
last_updated: 2026-03-21T09:39:28.086643+00:00
|
||||
last_updated: 2026-03-21T13:37:45.326992+00:00
|
||||
---
|
||||
|
||||
# Tools — backend-specialist
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
user: Unknown
|
||||
project: Company Site
|
||||
last_updated: 2026-03-21T09:39:28.087486+00:00
|
||||
last_updated: 2026-03-21T13:37:45.328056+00:00
|
||||
---
|
||||
|
||||
# User Context — Company Site
|
||||
|
||||
Reference in New Issue
Block a user