HANDOFF SESSION 100 VITTO FIXES
Documentation for Handoffs
HANDOFF: Session 100 — Vitto API Production Fixes
Handoff ID: SESSION-100-VITTO-FIXES From: Cowork Agent (Browser/Infrastructure — Paco's Cowork session) To: Cursor / Coding Agents Priority: HIGH Created: 2026-02-10 Session: 100 (continued) Status: READY FOR PICKUP Type: Bug Fixes — Vitto API Production Issues Confidence: 0.95
Context
After successfully deploying backend-vitto-api to Railway (deployment e468bde0, commit 077acde4f), the following runtime issues were observed in the deploy logs. These need code-level fixes before the next deployment.
Current Deploy Logs (Feb 9, 2026, 10:30 PM CST)
Starting Container
(node:1) [MONGOOSE] Warning: Duplicate schema index on {"expiresAt":1} found.
(node:1) [MONGOOSE] Warning: Duplicate schema index on {"userId":1} found.
[RouteDiscovery] Discovered 32 routes in 6 modules
🤖 VITTO Super-Agent API READY on port 3003 (Railway)
[VITTO-API] 1 - 02/10/2026, 4:40:00 AM WARN [ProactiveMonitor] [api-health] Alert: Services unreachable: backend-api, backend-ai-api, backend-docs-api
[VITTO-API] 1 - 02/10/2026, 4:45:00 AM WARN [ProactiveMonitor] [api-health] Alert: Services unreachable: backend-api, backend-ai-api, backend-docs-api
[VITTO-API] 1 - 02/10/2026, 4:45:00 AM WARN [ProactiveMonitor] [space-agents-health] Alert: Agent types unavailable: code, browser (0 agents online)
[VITTO-API] 1 - 02/10/2026, 4:50:00 AM WARN [ProactiveMonitor] [api-health] Alert: Services unreachable: backend-api, backend-ai-api, backend-docs-api
Health Status (verified)
| Service | Endpoint | Status |
|---|---|---|
| backend-api | https://api.gograb.space/api/health | ✅ 200 OK |
| backend-ai-api | https://ai-api.gograb.space/ai-api/health | ✅ 200 OK |
| backend-docs-api | https://docs-api.gograb.space/docs-api/health | ✅ 200 OK |
| backend-vitto-api | https://vitto-api.gograb.space/vitto-api/health | ✅ 200 OK |
All 4 services are healthy and responding. The warnings are caused by incorrect health check URL construction in the Vitto codebase, not by actual service outages.
Issue 1: ProactiveMonitor Health Check URLs Are Wrong (🔴 CRITICAL)
Logs:
WARN [ProactiveMonitor] [api-health] Alert: Services unreachable: backend-api, backend-ai-api, backend-docs-api
Frequency: Every 5 minutes, continuously since startup
Root Cause Analysis
The three backend client services construct health check URLs by stripping the API path prefix, which produces incorrect URLs when using the public domain names.
Current Railway Environment Variables (Vitto API):
BACKEND_API_URL="https://api.gograb.space/api"
BACKEND_AI_API_URL="https://ai-api.gograb.space/ai-api"
BACKEND_DOCS_API_URL="https://docs-api.gograb.space/docs-api"
What the health checks do vs. what they should do:
| Service | Code Does | Resulting URL | Actual Health Endpoint | Match? |
|---|---|---|---|---|
| backend-api | baseUrl.replace('/api', '') + '/health' |
https://api.gograb.space/health |
https://api.gograb.space/api/health |
❌ 404 |
| backend-ai-api | baseUrl.replace('/ai-api', '') + '/health/unified-health' |
https://ai-api.gograb.space/health/unified-health |
https://ai-api.gograb.space/ai-api/health |
❌ 404 |
| backend-docs-api | baseUrl.replace('/docs-api', '') + '/health' |
https://docs-api.gograb.space/health |
https://docs-api.gograb.space/docs-api/health |
❌ 404 |
Files to Fix
File 1: apis/backend-vitto-api/src/app/connectivity/backend-api-client.service.ts
// CURRENT (BROKEN):
async checkHealth(): Promise<boolean> {
try {
await firstValueFrom(
this.http.get(`${this.baseUrl.replace('/api', '')}/health`, { headers: this.headers, timeout: 5000 }),
);
return true;
} catch { return false; }
}
// FIX — use the actual health endpoint:
async checkHealth(): Promise<boolean> {
try {
await firstValueFrom(
this.http.get(`${this.baseUrl}/health`, { headers: this.headers, timeout: 5000 }),
);
return true;
} catch { return false; }
}
File 2: apis/backend-vitto-api/src/app/connectivity/backend-ai-client.service.ts
// CURRENT (BROKEN):
async checkHealth(): Promise<boolean> {
try {
await firstValueFrom(
this.http.get(`${this.baseUrl.replace('/ai-api', '')}/health/unified-health`, { headers: this.headers, timeout: 5000 }),
);
return true;
} catch { return false; }
}
// FIX — use the actual health endpoint:
async checkHealth(): Promise<boolean> {
try {
await firstValueFrom(
this.http.get(`${this.baseUrl}/health`, { headers: this.headers, timeout: 5000 }),
);
return true;
} catch { return false; }
}
File 3: apis/backend-vitto-api/src/app/connectivity/backend-docs-client.service.ts
// CURRENT (BROKEN):
async checkHealth(): Promise<boolean> {
try {
await firstValueFrom(
this.http.get(`${this.baseUrl.replace('/docs-api', '')}/health`, { headers: this.headers, timeout: 5000 }),
);
return true;
} catch { return false; }
}
// FIX — use the actual health endpoint:
async checkHealth(): Promise<boolean> {
try {
await firstValueFrom(
this.http.get(`${this.baseUrl}/health`, { headers: this.headers, timeout: 5000 }),
);
return true;
} catch { return false; }
}
Why This Fix Works
The env vars already include the path prefix (e.g., https://api.gograb.space/api), so the health endpoint is simply ${baseUrl}/health = https://api.gograb.space/api/health — which is exactly what returns 200 OK.
Also Consider
The BACKEND_API_INTERNAL_TOKEN env var is NOT configured in Railway. The backend clients use it as a Bearer token in the Authorization header. If health endpoints require auth, this needs to be set. Currently it defaults to empty string.
Issue 2: Space Agents Health Check — No Agents Online (🟡 MEDIUM)
Logs:
WARN [ProactiveMonitor] [space-agents-health] Alert: Agent types unavailable: code, browser (0 agents online)
Frequency: Every 15 minutes
Root Cause
The space-agents-health check calls BackendAiClientService.getLiveAgents() which hits GET ${BACKEND_AI_API_URL}/mcp/agents. It expects to find agents of type code and browser registered with the ai-api.
Currently, 0 agents are online because:
- No MCP code agents or browser agents have registered with ai-api
- The MCP circuit breaker on ai-api is permanently open (Issue 1 in the parent handoff
HANDOFF-SESSION-100-PRODUCTION-ISSUES.md)
Files
- Check definition:
apis/backend-vitto-api/src/app/proactive/checks/space-checks.service.ts(lines 63-101) - Agent lookup:
apis/backend-vitto-api/src/app/connectivity/backend-ai-client.service.ts→getLiveAgents()
Fix Options
- Short-term: Make the agent check non-critical — log at INFO level instead of WARN when no agents are expected in production
- Long-term: Deploy MCP agent servers that register with ai-api, or configure MCP integration properly (see parent handoff Issue 1)
- Defensive code: Add a config flag
REQUIRE_AGENTS=falseto disable this check when agents aren't expected
Issue 3: Mongoose Duplicate Schema Indexes (🟡 MEDIUM)
Logs:
[MONGOOSE] Warning: Duplicate schema index on {"expiresAt":1} found.
[MONGOOSE] Warning: Duplicate schema index on {"userId":1} found.
Root Cause
In the UserAgentMemorySchema, the expiresAt field has BOTH an inline index AND a separate schema.index() call:
File: libs/libs-api/backend-core/src/lib/schemas/user-agent-memory.schema.ts
// Line 122-123: Inline index on the field
@Prop({ type: Date, index: true })
expiresAt?: Date;
// Line 153: DUPLICATE — separate index call on the same field
UserAgentMemorySchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
Fix
Remove index: true from the @Prop decorator since the schema.index() call is needed for the TTL expireAfterSeconds option:
// Line 122-123: Remove index: true
@Prop({ type: Date })
expiresAt?: Date;
// Line 153: Keep this — it defines the TTL index
UserAgentMemorySchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
For userId: Check if there's a compound index that includes userId — if so, remove the index: true from the field definition to avoid the duplicate. The compound indexes at lines 144, 147, 150, 156, 159 already cover userId.
Issue 4: Missing BACKEND_API_INTERNAL_TOKEN Environment Variable (🟡 MEDIUM)
The three backend client services (BackendApiClientService, BackendAiClientService, BackendDocsClientService) all read BACKEND_API_INTERNAL_TOKEN for authenticating internal API calls between services.
Current state: Not configured in Railway → defaults to empty string → Authorization: Bearer header sent with all requests.
Fix
- Generate a shared internal token
- Add
BACKEND_API_INTERNAL_TOKEN=<token>to Railway env vars for:- backend-vitto-api
- backend-ai-api (if it validates this token)
- backend-api (if it validates this token)
- backend-docs-api (if it validates this token)
OR: If the health endpoints don't require auth (they typically don't), this may be lower priority. But other internal API calls between services likely need this token.
Issue 5: Remove Temporary DEPLOY_TRIGGER Variable (🟢 LOW)
A temporary DEPLOY_TRIGGER="1" environment variable exists in Railway for the Vitto API service. It was added to force a redeployment and is harmless but should be cleaned up.
Action: Remove DEPLOY_TRIGGER from Railway backend-vitto-api environment variables.
Summary: Action Priority Matrix
| # | Issue | Severity | Type | Effort |
|---|---|---|---|---|
| 1 | ProactiveMonitor health check URLs wrong | 🔴 CRITICAL | Code Fix (3 files) | ~15 min |
| 2 | Space agents health — no agents online | 🟡 MEDIUM | Code Fix / Config | ~30 min |
| 3 | Mongoose duplicate schema indexes | 🟡 MEDIUM | Schema Fix (1 file) | ~10 min |
| 4 | Missing BACKEND_API_INTERNAL_TOKEN | 🟡 MEDIUM | Env Var | ~5 min |
| 5 | Remove DEPLOY_TRIGGER env var | 🟢 LOW | Cleanup | ~1 min |
Related Handoffs
- Parent handoff:
docs/english/Handoffs/HANDOFF-SESSION-100-PRODUCTION-ISSUES.md— Contains 16 issues across all services (ai-api + vitto-api). The issues in THIS handoff are Vitto-specific and expand on Issue 15 from the parent.
Railway Reference
| Key | Value |
|---|---|
| Project ID | 8d9b4864-25f4-4c4e-b479-f5e49cea4001 |
| Service ID | 1acab221-cd3e-4c3f-9cbb-bcbc5feb7954 |
| Environment ID | 0d84c89d-6bc7-425c-8d17-14e0a5760041 |
| Branch | deploy/vitto-api |
| Active Deployment | e468bde0 (commit 077acde4f) |
| Port | 3003 |
| Domain | vitto-api.gograb.space |
Verification After Fixes
After deploying the code fixes, verify:
- Health check logs should stop — No more
[api-health] Alert: Services unreachablewarnings - Mongoose warnings should stop — No more duplicate index warnings on startup
- Health endpoint still works —
https://vitto-api.gograb.space/vitto-api/healthreturns 200 OK - ProactiveMonitor status — Call the ProactiveMonitor status endpoint to verify checks pass