Skip to main content

Common Issues

WebGPU Not Supported Error

Symptom: Error screen showing “WebGPU not supported. Please upgrade your browser.” Cause: Browser doesn’t support WebGPU (required as of February 2026) Solution: Upgrade to a WebGPU-compatible browser: Supported Browsers:
  • Chrome 113+ (recommended)
  • Edge 113+
  • Safari 18+ (macOS Sonoma or later)
  • Firefox Nightly (experimental)
Why WebGPU is Required:
  • All shaders use Three.js Shading Language (TSL)
  • TSL only compiles to WGSL (WebGPU Shading Language)
  • No WebGL fallback possible without rewriting all shaders
  • Procedural grass, terrain, particles all require WebGPU
Check WebGPU Support:
// In browser console
if (navigator.gpu) {
  console.log('WebGPU supported!');
} else {
  console.log('WebGPU not supported - upgrade browser');
}
Technical Details:
  • Commit: 3bc59db (February 26, 2026)
  • File: packages/shared/src/systems/client/ClientGraphics.ts
  • User-friendly error screen shows browser upgrade instructions

Characters Vanishing

Symptom: Characters disappear after page refresh Cause: Missing Privy credentials—each refresh creates a new anonymous identity Solution: Configure Privy authentication:
# packages/client/.env
PUBLIC_PRIVY_APP_ID=your-app-id

# packages/server/.env
PUBLIC_PRIVY_APP_ID=your-app-id
PRIVY_APP_SECRET=your-app-secret

Assets Not Loading

Symptom: 404 errors for models/avatars Cause: CDN container not running Solution:
bun run cdn:up
Or ensure you’re using bun run dev which starts it automatically.

Database Schema Errors

Symptom: Errors about missing columns or tables Cause: Schema changed but migrations not run Solution:
cd packages/server
bunx drizzle-kit push
For a complete reset (destroys data):
docker stop hyperscape-postgres
docker rm hyperscape-postgres
docker volume rm hyperscape-postgres-data
docker volume rm server_postgres-data
bun run dev

Manifest Validation Errors

Symptom: DataManager validation errors about invalid JSON in manifest files Cause: Invalid JSON syntax in manifest files (trailing commas, missing quotes, etc.) Solution: Recent commits fixed several manifest JSON errors. Update to latest code:
git pull origin main
bun install
bun run build
If you’re editing manifests manually, validate JSON syntax:
# Validate a manifest file
cat packages/server/world/assets/manifests/npcs.json | jq .
Common Issues:
  • Trailing commas in JSON arrays/objects
  • Missing quotes around property names
  • Incorrect .gitignore negation for manifest files
Recent Fixes:
  • Fixed invalid manifest JSONs causing DataManager validation errors (commit aa1ea2d)
  • Corrected .gitignore manifest negation to properly track manifest files (commit 1f4551c)
  • All manifest files now tracked in git for CI test data availability (commit 2dddf28)

Port Conflicts

Symptom: “Port already in use” errors Solution: Kill processes on conflicting ports:
lsof -ti:3333 | xargs kill -9   # Client
lsof -ti:5555 | xargs kill -9   # Server
lsof -ti:8080 | xargs kill -9   # CDN
lsof -ti:4001 | xargs kill -9   # ElizaOS

Build Errors

Symptom: Compilation fails Solution: Clean rebuild:
bun run clean
rm -rf node_modules packages/*/node_modules
bun install
bun run build

ESLint Crashes with ajv TypeError

Symptom: ESLint crashes with TypeError: Class extends value undefined is not a constructor or null related to ajv Cause: Forcing ajv@8 on @eslint/eslintrc which requires ajv@6 for Draft-04 schema support Solution: Update to latest code (commit b344d9e fixed this):
git pull origin main
bun install
Technical Details:
  • Removed ajv>=8.18.0 override from root package.json
  • @eslint/eslintrc needs ajv@6 for JSON Schema Draft-04 support
  • Forcing ajv@8 caused TypeError crash in ESLint initialization
  • Security fix for ajv (GHSA-2g4f-4pwh-qvx6) applied only to packages that support ajv@8

Drizzle Migration Failures in CI

Symptom: Server migration code fails with “table already exists” errors in CI, or migration 0050 fails with “relation already exists” (42P07) on fresh databases Cause: Multiple issues with migration system:
  1. Running drizzle-kit push separately creates tables without populating migration journal
  2. Migration 0050 duplicated CREATE TABLE statements from earlier migrations without IF NOT EXISTS guards
  3. SKIP_MIGRATIONS=true didn’t skip table validation, causing failures when schema created externally
Solution: Update to latest code (commits eb8652a, 6a5f4ee, e4b6489 fixed this): For CI/Integration Tests:
# ✅ Use drizzle-kit push + SKIP_MIGRATIONS for declarative schema
- name: Create database schema
  run: bunx drizzle-kit push
  
- name: Run tests
  run: bun test:integration
  env:
    SKIP_MIGRATIONS: true  # Skip ALL migration checks
For Production:
# ✅ Let server handle migrations normally
- run: bun run start
# No SKIP_MIGRATIONS, no drizzle-kit push
Technical Details:
  • Commit eb8652a: CI now uses drizzle-kit push for declarative schema creation
  • Commit 6a5f4ee: SKIP_MIGRATIONS=true now skips table validation AND migration recovery loop
  • Commit e4b6489: Migration 0050 fixed with IF NOT EXISTS guards for idempotency
  • Server’s built-in migrations have FK ordering issues (migration 0050 references arena_rounds from older migrations)
  • drizzle-kit push creates schema declaratively without these problems
  • SKIP_MIGRATIONS=true tells server to skip ALL migration-related checks when schema is created externally
Migration 0050 Fix Details: Migration 0050 previously duplicated CREATE TABLE statements from earlier migrations:
  • agent_duel_stats (from migration 0039)
  • arena_fee_shares
  • arena_staking_points
  • wallet_links
On fresh databases, running all migrations sequentially caused 42P07 errors when the same table was created twice. Now all CREATE TABLE and CREATE INDEX statements use IF NOT EXISTS guards.

Circular Dependency Build Errors

Symptom: TypeScript errors about missing types from @hyperscape/shared or @hyperscape/procgen Cause: Circular dependencies between packages during clean builds Solution: The build system handles this automatically with resilient patterns:
  • procgen ↔ shared: Uses tsc || echo to exit 0 even with circular dep errors
  • plugin-hyperscape ↔ shared: Uses --skipLibCheck in declaration generation
  • Packages produce partial output sufficient for downstream consumers
If you still see errors:
# Build shared first to create dist/ directory
cd packages/shared
bun run build

# Then build dependent packages
cd ../procgen
bun run build

cd ../plugin-hyperscape
bun run build

PhysX Build Fails

Symptom: Errors during PhysX compilation Cause: PhysX WASM build requires emscripten Solution: PhysX is pre-built and committed. If you must rebuild:
cd packages/physx-js-webidl
./make.sh   # Requires emscripten toolchain

Tests Failing

Symptom: Tests timeout or fail unexpectedly Causes:
  • Server running during tests
  • Stale test data
  • Port conflicts
  • CI environment variance (slower than local)
  • Missing WebGPU mocks for Three.js WebGPU renderer
Solution:
# Stop any running servers
lsof -ti:5555 | xargs kill -9

# Check logs
ls /logs/

# Run tests
npm test
CI-Specific Issues: Recent commits have adjusted test timeouts for CI reliability:
  • Geometry validation: Increased to 120s for intensive procgen tests
  • Benchmark thresholds: Relaxed for NPCTickProcessor to account for CI variance
  • Vitest timeout: Global timeout increased to prevent flaky failures
  • Performance tests: Adjusted heap growth and scaling thresholds for parallel test contention
If tests pass locally but fail in CI, check if timeouts need adjustment for your specific test.

Integration Tests Fail with “anvil: command not found”

Symptom: Integration tests fail because the anvil binary is missing Cause: Foundry toolchain not installed in CI environment Solution: Update to latest code (commit b344d9e fixed this):
# .github/workflows/integration.yml now includes:
- name: Install Foundry
  uses: foundry-rs/foundry-toolchain@v1
For local development, install Foundry:
curl -L https://foundry.paradigm.xyz | bash
foundryup

Test Suite Fails with WebGPU Errors

Symptom: Tests fail with “GPUShaderStage is not defined” or similar WebGPU errors Cause: Three.js WebGPU renderer expects browser globals that don’t exist in test environment Solution: Update to latest code (commit 25ba63c fixed this): Technical Details:
  • Added vitest.setup.ts to mock WebGPU browser globals
  • Mocks: GPUShaderStage, GPUBufferUsage, GPUTextureUsage, etc.
  • Required by Three.js WebGPU renderer in tests
  • Fixed in packages/server/vitest.setup.ts

ArenaService Tests Fail After Refactor

Symptom: ArenaService tests fail with “Cannot spy on private method” errors Cause: Refactored ArenaService architecture moved methods to sub-services Solution: Update to latest code (commit 25ba63c fixed this): Technical Details:
  • Added protected passthrough methods on ArenaService for test spying
  • Methods: getDb, getEligibleAgents, findReferralMappingForWalletNetwork, etc.
  • Database mock helper: setDbMock properly configures world.getSystem(“database”) mock
  • Some tests skipped pending deeper refactoring (85 skipped, 1569 passing)

WebSocket Connection Failed

Symptom: Can’t connect to game server Causes:
  • Server not running
  • Wrong port configuration
  • Firewall blocking
Solution:
  1. Verify server is running: lsof -i:5555
  2. Check client config: PUBLIC_WS_URL
  3. Ensure no firewall blocks

Hot Reload Not Working

Symptom: Changes don’t appear in browser Causes:
  • Build cache stale
  • Wrong directory
Solution:
bun run dev:reset

Database Pool Starvation

Symptom: “200 pending operations” warnings, game freezes during batch operations (fletching, smithing) Cause: Concurrent inventory writes exhausting database connection pool Solution: Update to latest code (PR #823 fixed this). The system now uses write coalescing:
// Collapses N concurrent writes into ≤2 DB transactions per player
// Before: 100 fletching completions = 200 sequential transactions
// After: 100 fletching completions = 2 transactions per player
Technical Details:
  • Write coalescing keeps only the latest inventory snapshot
  • At most 2 transactions per player: one active + one queued
  • All waiting callers resolve when batch completes
  • Prevents PostgreSQL deadlocks and pool exhaustion
Verification: Check packages/server/src/systems/DatabaseSystem/index.ts for inventoryWriteActive and inventoryWriteQueued maps.

Camera Facing Backwards on Fresh Load

Symptom: Camera initializes in front of player, causing backwards movement controls Cause: Camera spherical coordinates initialized with theta=0 instead of theta=Math.PI Solution: Update to latest code (PR #829 fixed this) Technical Details:
  • Camera uses spherical coordinates (radius, phi, theta)
  • theta=0 places camera in front of player (incorrect)
  • theta=Math.PI places camera behind player (correct third-person view)
  • Fixed in ClientCameraSystem.ts initialization and reset methods

Entity Outlines Showing Wrong Colors

Symptom: Entity highlights show incorrect color grading when hovering, even with post-processing disabled Cause: Post-processing outline pass shares shader pipeline with LUT color grading, causing stale LUT data to leak into outline-only rendering Solution: Update to latest code (PR #829 fixed this) Technical Details:
  • LUT intensity now zeroed when color grading is disabled
  • Rendering routes through composer even when post-processing is off
  • Ensures entity highlights work correctly without color grading artifacts
  • Fixed in ClientGraphics.ts and PostProcessingFactory.ts

Remote Players Facing Sideways

Symptom: Other players appear to face sideways or show T-pose ghosts in multiplayer Cause: Missing quaternion sync and transform updates after async avatar loading Solution: Update to latest code (PR #875 fixed this) Technical Details:
  • base.quaternion now synced in PlayerRemote for correct facing direction
  • Force transform update after async avatar load prevents T-pose ghosts
  • Spatial index updated after teleport/respawn so sendToNearby reaches players at new location
  • Authoritative position broadcast to all players on join
  • Fixed in PlayerRemote.ts and ServerNetwork/index.ts

Equipment Not Visible on Other Players

Symptom: Equipment doesn’t appear on remote players, or only shows after reconnect Cause: Equipment packets sent before VRM avatar loaded, or lost during disconnect Solution: Update to latest code (PR #875 fixed this) Technical Details:
  • Subscribe to AVATAR_LOAD_COMPLETE to replay cached equipment when VRM loads
  • Re-send equipment on socket reconnect (recovers packets lost during disconnect)
  • Send existing players’ equipment to joiner and broadcast joiner’s equipment
  • Use all 11 EQUIPMENT_SLOT_NAMES instead of hardcoded 6 slots
  • Fixed in EquipmentVisualSystem.ts and ServerNetwork/index.ts

Duel Loser Stuck in Arena

Symptom: After duel ends, loser is stuck in arena with frozen physics and cannot move or respawn Cause: Winner’s health restore exception prevented loser’s health restore from executing Solution: Update to latest code (PR #875 fixed this) Technical Details:
  • Split health restores into individual try/catch blocks
  • Previously both restorePlayerHealth calls were in single try/catch
  • If winner’s restore triggered exception in any PLAYER_RESPAWNED handler, loser’s restore was skipped
  • Left loser with frozen physics, isDying=true, and no playerRespawned/playerSetDead packets
  • Each restore now individually wrapped, matching teleport pattern
  • Fixed in DuelCombatResolver.ts

PvP Ranged Attacks Granting Wrong XP

Symptom: Killing players with ranged attacks in duels grants Strength XP instead of Ranged XP Cause: XP calculation used player’s melee attack style instead of actual weapon type Solution: Update to latest code (PR #875 fixed this) Technical Details:
  • PlayerDeathSystem now detects weapon type (bow/crossbow/staff) for PvP kills
  • Previously used player’s melee attack style, incorrectly granting Strength XP
  • Now matches MobEntity logic: inspect actual weapon type for XP calculation
  • Fixed in PlayerDeathSystem.ts

Logs

Server Logs

Check terminal output where bun run dev is running.

Test Logs

ls packages/server/logs/

Docker Logs

docker logs hyperscape-postgres
docker logs hyperscape-cdn

Database Prepared Statements Error (XX000)

Symptom: Database queries fail with error code XX000 when using Supabase Supavisor pooler Cause: Supavisor connection pooler doesn’t support prepared statements in transaction mode Solution: Update to latest code (commits 8aaaf28, f7ab9f7 fixed this). Prepared statements are now disabled for Supavisor:
// From packages/server/src/database/client.ts
const client = postgres(connectionString, {
  prepare: false,  // Disable prepared statements for Supavisor compatibility
  // ... other options
});
Technical Details:
  • Supavisor pooler operates in transaction mode
  • Transaction mode doesn’t support prepared statements (PostgreSQL limitation)
  • Disabling prepared statements trades minor performance for compatibility
  • Only affects Supabase deployments using Supavisor pooler
  • Local PostgreSQL and other providers unaffected
When to Disable:
  • Using Supabase with Supavisor pooler
  • Getting XX000 errors on database queries
  • Connection string contains pooler.supabase.com
When to Keep Enabled:
  • Local PostgreSQL development
  • Direct PostgreSQL connections (no pooler)
  • PgBouncer in statement mode
  • Neon, Railway, or other providers without transaction pooling

Streaming WebGPU Backend Issues (RTX 4090)

Symptom: WebGPU rendering fails or crashes on RTX 4090 GPUs in streaming mode Cause: ANGLE backend defaulting to GL instead of Vulkan for RTX 4090 Solution: Update to latest code (commit 80bb06ed fixed this). ANGLE now uses Vulkan backend for RTX 4090:
// From browser-capture.ts
const gpuBackend = gpuModel?.includes('4090') ? 'vulkan' : 'gl';
const chromeArgs = [
  '--use-angle=vulkan',  // Force Vulkan for RTX 4090
  '--enable-features=Vulkan',
  // ... other flags
];
Technical Details:
  • RTX 4090 requires Vulkan backend for optimal WebGPU performance
  • GL backend causes rendering issues and crashes
  • Automatically detected based on GPU model string
  • Only affects streaming/headless mode with RTX 4090
  • Fixed in packages/server/src/streaming/browser-capture.ts
Verification: Check Chrome flags in streaming logs for --use-angle=vulkan when RTX 4090 is detected.

Deployment Issues

Docker Build Failures

Symptom: Native module compilation fails in minimal Docker images Cause: Missing build tools in base image Solution: Ensure build-essential is installed:
# From Dockerfile.server
RUN apt-get update && apt-get install -y \
    build-essential \
    git-lfs \
    python3 \
    python3-pip
Recent Fixes:
  • Added build-essential for native module compilation (commit bd2aad9)
  • Added git-lfs for asset checks (commit 87b3c1a)
  • Added unzip for bun install (commit 18d6126)

DNS Resolution Failures

Symptom: Cannot resolve external domains in Docker containers Cause: Default DNS servers not working in container environment Solution: Overwrite resolv.conf with Google DNS:
# From deploy scripts
echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/resolv.conf
Recent Fix:
  • Changed from appending to overwriting resolv.conf (commit fd17248)

Asset Download in Production

Symptom: Production builds try to download assets from Git LFS Cause: Asset download script runs in production environment Solution: Set CI=true to skip asset download:
# In production environment
CI=true bun run build
Recent Fix:
  • Added CI=true check to skip asset download in production (commit 28bf9fb)

Streaming Dependencies Missing

Symptom: Streaming mode fails with missing Playwright or ffmpeg Cause: Playwright dependencies and ffmpeg not installed in deployment image Solution: Install required dependencies:
# Add to Dockerfile
RUN npx playwright install-deps
RUN apt-get install -y ffmpeg
Recent Fix:
  • Added Playwright deps and ffmpeg for streaming (commit 5920467)

CORS Issues in Betting Service

Symptom: Preflight OPTIONS requests fail from betting frontend Cause: Missing CORS configuration or max-age header Solution: Configure CORS to allow all origins with max-age:
// From keeper CORS config
fastify.register(cors, {
  origin: true,  // Allow all origins
  credentials: true,
  maxAge: 86400,  // 24 hours
});
Recent Fixes:
  • Allow all origins and add CORS max-age (commit 7256b07)
  • Allow hyperscape-betting.pages.dev origin (commit fb3b9cd)
  • Allow pointer events on stream-bg for Twitch embed interaction (commit 0925171)

Streaming Issues

Stream Not Appearing on Twitch/Kick/X

Symptom: FFmpeg running but stream not visible on platforms Cause: Incorrect stream keys or RTMP URLs Solution: Verify stream keys are configured correctly:
# Check environment variables
echo $TWITCH_STREAM_KEY
echo $KICK_STREAM_KEY
echo $X_STREAM_KEY

# Check .env file
cat packages/server/.env | grep STREAM_KEY

# Check PM2 environment
bunx pm2 show hyperscape-duel | grep STREAM_KEY
Common Issues:
  • Stale stream keys in shell environment overriding .env file
  • Missing /app path in Kick RTMP URL
  • Wrong RTMP URL format
Correct RTMP URLs (as of Feb 26, 2026):
# Twitch
TWITCH_RTMP_URL=rtmp://live.twitch.tv/app

# Kick (uses RTMPS)
KICK_RTMP_URL=rtmps://fa723fc1b171.global-contribute.live-video.net/app

# X/Twitter
X_RTMP_URL=rtmp://sg.pscp.tv:80/x
Stream Key Management: Stream keys must be explicitly unset and re-exported before PM2 start:
# From scripts/deploy-vast.sh
unset TWITCH_STREAM_KEY X_STREAM_KEY X_RTMP_URL KICK_STREAM_KEY KICK_RTMP_URL
source /root/hyperscape/packages/server/.env
bunx pm2 start ecosystem.config.cjs
Debugging: Check RTMP status file:
cat packages/server/public/live/rtmp-status.json
Check FFmpeg processes:
ps aux | grep ffmpeg
Check PM2 logs for streaming keywords:
bunx pm2 logs hyperscape-duel --lines 200 | grep -iE "rtmp|stream|ffmpeg|destination"
Recent Fixes:
  • Fixed Kick RTMP URL from ingest.kick.com to correct IVS endpoint (commit 5dbd239)
  • Added all stream keys to CI/CD secrets flow (commit 5dbd239)
  • Fixed stream key environment variable handling in deploy scripts (commits 7ee730d, a71d4ba)

WebGPU Crashes on RTX 5060 Ti

Symptom: Chrome crashes or freezes when using WebGPU on RTX 5060 Ti GPUs Cause: Broken Vulkan ICD on RTX 5060 Ti Solution: Use GL ANGLE backend instead of Vulkan:
# Set environment variable
CHROME_BACKEND=angle

# Or use Chrome flags
--use-gl=angle --use-angle=gl
Recent Fixes:
  • Removed RTX 5060 Ti from GPU search (commit 30cacb0)
  • Switch to GL ANGLE backend for RTX 5060 Ti (commit 0257563)
  • WebGPU-safe Chrome flags (removed aggressive GPU opts) (commit f3aa787)

FFmpeg SIGSEGV in Static Builds

Symptom: FFmpeg crashes with segmentation fault when using static builds Cause: Static FFmpeg builds incompatible with some system configurations Solution: Use system FFmpeg instead:
# Install system FFmpeg
apt-get install -y ffmpeg

# Verify installation
ffmpeg -version
Recent Fixes:
  • Use system FFmpeg to avoid static build SIGSEGV (commits 55a07bd, 536763d)

Streaming Black Screen

Symptom: Stream shows black screen instead of game Causes:
  1. GPU not accessible in headless mode
  2. Wrong Chrome backend
  3. Missing Xvfb for headful mode
Solutions:
# Try headful mode with Xvfb
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99
bun run dev:streaming

# Or use swiftshader CPU fallback
CHROME_BACKEND=swiftshader bun run dev:streaming
Recent Fixes:
  • Switch back to headful mode for GPU compositing with Xvfb (commit 5e4c6f1)
  • Use swiftshader + headless + WebGL for stable streaming (commit ae42beb)

Chrome Dev Channel Not Found

Symptom: Cannot find Chrome Dev channel executable on Vast.ai Cause: Chrome Dev not installed or wrong path Solution: Install Chrome Dev channel:
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list
apt-get update
apt-get install -y google-chrome-unstable

# Use in Playwright
executablePath: '/usr/bin/google-chrome-unstable'
Recent Fixes:
  • Use Chrome Dev channel for WebGPU support on Vast.ai (commits ba8bd53, d824163)

Tauri Build Fails with Empty APPLE_CERTIFICATE

Symptom: Tauri macOS builds fail with SecKeychainItemImport error even when not doing a release build Cause: Tauri bundler attempts code signing whenever APPLE_CERTIFICATE env var exists, even if empty Solution: Update to latest code (commit 15250d2 fixed this) Technical Details:
  • Build workflow now split into Unsigned and Release variants
  • Signing env vars only present during actual releases
  • Non-release builds no longer set APPLE_CERTIFICATE=''
  • macOS unsigned builds use --no-bundle instead of --bundles app (app bundle type is macOS-only)
  • iOS builds are release-only (unsigned iOS always fails with “Signing requires a development team”)
  • Windows builds include retry logic for transient NPM registry errors
  • File: .github/workflows/build-app.yml
  • Commit: 15250d2 (Feb 25, 2026)

Linux/Windows Desktop Builds Fail in CI

Symptom: Tauri desktop builds fail on Linux/Windows with “app bundle type is macOS-only” error Cause: --bundles app flag is macOS-specific, causes Linux/Windows builds to fail Solution: Update to latest code (commit f19a704 fixed this) Technical Details:
  • Replaced --bundles app with --no-bundle for unsigned builds
  • app bundle type is macOS-only, causing Linux/Windows to fail
  • Made beforeBuildCommand cross-platform using Node.js instead of Unix shell test command
  • Split artifact upload: release builds upload bundles, unsigned builds upload raw binaries
  • File: .github/workflows/build-app.yml
  • Commit: f19a704 (Feb 26, 2026)

Cloudflare Origin Lock Blocking API Access

Symptom: Frontend cannot access API directly, getting origin lock errors Cause: Cloudflare origin lock preventing direct frontend API access Solution: Update to latest code (commit 3ec9826 fixed this) Technical Details:
  • Disabled cloudflare origin lock in server configuration
  • Allows direct API access from frontend
  • File: packages/server/ (server configuration)
  • Commit: 3ec9826 (Feb 25, 2026)

Cloudflare Pages Worker Deployment Error

Symptom: Cloudflare Pages deployment fails with worker deployment error Cause: Missing build output directory specification in Cloudflare configuration Solution: Update to latest code (commit 1af02ce fixed this) Technical Details:
  • Specified pages build output dir in Cloudflare configuration
  • Cloudflare Pages deployments now succeed
  • Commit: 1af02ce (Feb 25, 2026)

Cloudflare Wrangler Configuration Issues

Symptom: Cloudflare Pages deployment fails with configuration errors or uses wrong directive Cause: Incorrect wrangler.toml configuration for Pages deployment Solution: Update to latest code (commit 42a1a0e fixed this) Technical Details:
  • Switched from pages_build_output_dir to [assets] directive
  • Works better with wrangler deploy for static asset hosting
  • Deploy command should be empty in Cloudflare dashboard
  • File: packages/client/wrangler.toml
  • Commit: 42a1a0e (Feb 26, 2026)

Root Wrangler Config Conflicts with Pages Project

Symptom: Cloudflare deployment confusion between Worker and Pages projects Cause: Root wrangler.toml named “hyperscape-betting” conflicts with “hyperscape” Pages project Solution: Update to latest code (commit f19a704 fixed this) Technical Details:
  • Removed root wrangler.toml to avoid deployment confusion
  • Correct Pages configuration is in packages/client/wrangler.toml
  • To complete fix, update Cloudflare Dashboard:
    1. Workers & Pages → hyperscape (Worker) → Settings → disconnect GitHub
    2. Workers & Pages → hyperscape (Pages) → Settings → connect GitHub
  • Commit: f19a704 (Feb 26, 2026)

Assets Not Found After Fresh Clone

Symptom: Server fails to start with “No world areas defined” or manifest validation errors Cause: Assets directory not cloned from HyperscapeAI/assets repository Solution: Assets are automatically cloned during bun install. If missing:
# Manual asset sync
bun run assets:sync

# Or re-run install
bun install
Technical Details:
  • Assets are sourced from HyperscapeAI/assets repository
  • scripts/ensure-assets.mjs runs during bun install postinstall hook
  • Local dev: Full clone with LFS (~200MB)
  • CI: Shallow clone without LFS (manifests only, ~1MB)
  • Entire packages/server/world/assets/ directory is gitignored
Verification:
# Check if assets exist
ls packages/server/world/assets/manifests/

# Should see:
# items/, gathering/, recipes/, npcs.json, stores.json, etc.

Model Cache Issues

Symptom: Missing objects in models (e.g., altars), white/wrong colored textures after restart, or grey trees in WebGPU builds Cause: Bugs in IndexedDB processed model cache (fixed in PR #935, commit c98f1cc, Feb 25, 2026) Solution: Update to latest code. The cache now uses:
  • Object-identity mapping instead of name-based lookup (fixes missing objects)
  • Raw RGBA pixel extraction for textures (fixes lost textures)
  • Duck-type property checks for materials (fixes grey trees in WebGPU)
Temporary Workaround: Disable the cache:
// In browser console
localStorage.setItem('disable-model-cache', 'true');
Technical Details: Bug #1 - Missing Objects (e.g., altars):
  • Problem: serializeNode used findIndex-by-name to map hierarchy nodes to mesh data. Models with duplicate mesh names (common: "", “Cube”, “Cube”) all resolved to the same index. During deserialization, Three.js add() auto-removes from previous parent, so only the last reference survived.
  • Fix: Use Map<Object3D, number> identity map built during traversal instead of name-based lookup
  • Impact: All objects in models now render correctly, including complex multi-mesh models like altars
Bug #2 - Lost Textures (white/wrong colors after restart):
  • Problem: Textures were serialized as ephemeral blob: URLs but never reloaded during deserialization. After page refresh, blob URLs became invalid, leaving models white or incorrectly colored.
  • Fix: Extract raw RGBA pixels via canvas getImageData (synchronous) and restore as THREE.DataTexture — no async loading race conditions
  • Impact: Textures persist correctly across page refreshes, models maintain correct colors
Bug #3 - Grey Trees in WebGPU Builds:
  • Problem: createDissolveMaterial used instanceof MeshStandardMaterial which fails for MeshStandardNodeMaterial in the WebGPU build where they are separate classes
  • Fix: Replaced with duck-type property check (src.color && src.roughness !== undefined)
  • Impact: Tree materials render correctly in WebGPU builds instead of appearing grey
Additional Improvements:
  • Added localStorage.setItem('disable-model-cache', 'true') to bypass cache for debugging
  • Error logging on IndexedDB put/transaction failures
  • Cache version bumped to 3 to invalidate broken entries
  • File: packages/shared/src/utils/rendering/ModelCache.ts
  • PR: #935 | Commit: c98f1cc (Feb 25, 2026)
See Model Cache System for complete details.

Terrain Height Offset Issues

Symptom: Players/entities positioned 50m above or below expected terrain height Cause: Tile index and grid index calculations didn’t account for PlaneGeometry’s centered coordinate system Solution: Update to latest code (commit 21e0860 fixed this) Technical Details:
  • Tile Index Bug: Math.floor(worldX/TILE_SIZE) doesn’t account for centered geometry
    • PlaneGeometry uses [-50, +50] range, not [0, 100]
    • Fixed with worldToTerrainTileIndex() canonical helper
  • Grid Index Bug: Formula omitted halfSize offset from PlaneGeometry’s centered range
    • Fixed with localToGridIndex() canonical helper
    • Applied to both getHeightAtCached() and getTerrainColorAt()
  • Key Format Bug: getTerrainColorAt() had comma-vs-underscore typo preventing tile lookups
    • Changed from ${tileX},${tileZ} to ${tileX}_${tileZ}
Impact: Terrain height queries now return correct values, fixing player/entity positioning File: packages/shared/src/systems/shared/world/TerrainSystem.ts

Cyclic Dependency Build Errors

Symptom: TypeScript errors about missing types from @hyperscape/shared or @hyperscape/procgen, or Turbo detecting circular dependencies Cause: Circular dependencies between packages during clean builds Solution: Update to latest code (commits f355276, 3b9c0f2, 05c2892 fixed shared/procgen cycle). The build system handles this automatically with resilient patterns:
  • procgen ↔ shared: Fully broken cycle via peerDependencies + devDependencies
    • Commit f355276: Moved procgen from dependencies to optional peerDependencies in shared
    • Commit 3b9c0f2: Removed cross-references entirely from both package.json files
    • Commit 05c2892: Added procgen as devDependency in shared for TypeScript type resolution
    • Turbo treats peerDependencies as graph edges, so peerDependencies alone was insufficient
    • devDependencies are not followed by turbo’s ^build topological ordering (no cycle)
    • Imports still resolve at runtime via bun workspace resolution (both packages always installed together)
  • plugin-hyperscape ↔ shared: Uses --skipLibCheck in declaration generation
  • Packages produce partial output sufficient for downstream consumers
If you still see errors:
# Build shared first to create dist/ directory
cd packages/shared
bun run build

# Then build dependent packages
cd ../procgen
bun run build

cd ../plugin-hyperscape
bun run build
Recent Fixes:
  • Commit 05c2892 (Feb 26, 2026): Added procgen as devDependency for TypeScript type resolution
  • Commit 3b9c0f2 (Feb 26, 2026): Fully broke shared↔procgen cycle by removing cross-references
  • Commit f355276 (Feb 25, 2026): Initial fix moving procgen to peerDependencies
  • Files: packages/shared/package.json, packages/procgen/package.json

Shared/Procgen Type Resolution Issues

Symptom: TypeScript can’t find @hyperscape/procgen module declarations during type checking in shared package Cause: procgen removed from dependencies to break circular dependency, but TypeScript still needs it for type resolution Solution: Update to latest code (commit 05c2892 fixed this) Technical Details:
  • Added procgen as devDependency in shared’s package.json
  • devDependencies are not followed by turbo’s ^build topological ordering (doesn’t create cycle)
  • Ensures bun links the package so TypeScript can find module declarations during type checking
  • Imports still resolve at runtime via bun workspace resolution
  • File: packages/shared/package.json
  • Commit: 05c2892 (Feb 26, 2026)

ESLint Crashes in Asset Forge

Symptom: ESLint crashes with errors about import/order rule using removed sourceCode.getTokenOrCommentBefore API Cause: eslint-plugin-import@2.32.0 is incompatible with ESLint 10 - uses removed API Solution: Update to latest code (commits cadd3d5, b5c762c fixed this) Technical Details:
  • Disabled cascaded import/order rule in asset-forge’s flat config
  • Used eslint src instead of eslint . --ext .ts,.tsx to avoid linting entire directory
  • Prevents eslint-plugin-import’s import/order rule from crashing
  • Files: packages/asset-forge/eslint.config.mjs, packages/asset-forge/package.json
  • Commits: cadd3d5, b5c762c (Feb 26, 2026)

Cloudflare Pages Deploy Fails with Wrangler Config Error

Symptom: Cloudflare Pages deployment fails with configuration errors Cause: Incorrect wrangler.toml configuration for Pages deployment Solution: Update to latest code (commit 42a1a0e fixed this) Technical Details:
  • Switched from pages_build_output_dir to [assets] directive
  • Works better with wrangler deploy for static asset hosting
  • Deploy command should be empty in Cloudflare dashboard
  • File: packages/client/wrangler.toml
  • Commit: 42a1a0e (Feb 26, 2026)

Root Wrangler Config Conflicts with Pages Project

Symptom: Cloudflare deployment confusion between Worker and Pages projects Cause: Root wrangler.toml named “hyperscape-betting” conflicts with “hyperscape” Pages project Solution: Update to latest code (commit f19a704 fixed this) Technical Details:
  • Removed root wrangler.toml to avoid deployment confusion
  • Correct Pages configuration is in packages/client/wrangler.toml
  • To complete fix, update Cloudflare Dashboard:
    1. Workers & Pages → hyperscape (Worker) → Settings → disconnect GitHub
    2. Workers & Pages → hyperscape (Pages) → Settings → connect GitHub
  • Commit: f19a704 (Feb 26, 2026)

Linux/Windows Desktop Builds Fail in CI

Symptom: Tauri desktop builds fail on Linux/Windows with “app bundle type is macOS-only” error Cause: --bundles app flag is macOS-specific, causes Linux/Windows builds to fail Solution: Update to latest code (commit f19a704 fixed this) Technical Details:
  • Replaced --bundles app with --no-bundle for unsigned builds
  • app bundle type is macOS-only, causing Linux/Windows to fail
  • Made beforeBuildCommand cross-platform using Node.js instead of Unix shell test command
  • Split artifact upload: release builds upload bundles, unsigned builds upload raw binaries
  • File: .github/workflows/build-app.yml
  • Commit: f19a704 (Feb 26, 2026)

Mage Agents Not Attacking in Duels

Symptom: Mage agents stand idle during duels, no spell projectiles visible Cause: Combat state key mismatch between CombatStateService and EmbeddedHyperscapeService Solution: Update to latest code (PR #933 fixed this) Technical Details:
  • CombatStateService syncs abbreviated keys (data.c/data.ct) for network efficiency
  • EmbeddedHyperscapeService.getGameState() only read full keys (data.inCombat/data.combatTarget)
  • DuelCombatAI always saw inCombat=false and flooded executeAttack every tick
  • Fixed by reading both abbreviated and full keys:
    inCombat: !!(data.inCombat || data.combatTarget || data.c || data.ct),
    currentTarget: (data.combatTarget as string) || (data.ct as string) || null,
    
  • File: packages/server/src/eliza/EmbeddedHyperscapeService.ts
  • Commit: 82ff784 (Feb 25, 2026)

Duplicate Magic Projectiles

Symptom: Magic attacks spawn two projectiles, runes consumed twice Cause: TOCTOU race condition in handleMagicAttack cooldown claim Solution: Update to latest code (PR #933 fixed this) Technical Details:
  • Cooldown was checked early but claimed after async consumeRunesForSpell call
  • With combat state bug flooding attacks, two concurrent invocations could both pass cooldown check
  • Fixed by moving cooldown claim before async rune consumption:
    // Claim cooldown BEFORE async rune consumption
    this.ctx.combatSystem.setNextAttackTick(attackerId, nextAttackTick);
    this.ctx.combatSystem.enterCombat(attackerId, targetId, weaponType);
    
    // THEN consume runes (async operation)
    await this.ctx.runeService.consumeRunesForSpell(attackerId, spell);
    
  • File: packages/shared/src/systems/shared/combat/handlers/MagicAttackHandler.ts
  • Commit: 82ff784 (Feb 25, 2026)

Players Sinking Into Duel Arena Floors

Symptom: Players/agents appear to sink ~0.4m into duel arena floors, grass grows through floor surfaces Cause: Flat zones were removed from terrain system, causing getHeightAt() to return raw procedural terrain height instead of floor-level height Solution: Update to latest code (PR #911 fixed this) Technical Details:
  • DuelArenaVisualsSystem now registers flat zones programmatically for all 8 floor areas
  • Affected areas: 6 arenas (2×3 grid), lobby (60×30), hospital (20×15)
  • Terrain height queries now return correct floor-level values
  • Terrain mesh is carved under floors via flat zone registration
  • File: packages/shared/src/systems/client/DuelArenaVisualsSystem.ts
  • Commit: 7a60135 (Feb 25, 2026)

Cannot Click to Move in Duel Arenas

Symptom: Click targets go underground in duel arenas, players cannot move Cause: Building footprint validation rejecting arena-floor raycast hits Solution: Update to latest code (commit 2435423 fixed this) Technical Details:
  • RaycastService now skips building footprint validation for arena-floor raycast hits
  • File: packages/shared/src/systems/client/interaction/services/RaycastService.ts
  • Commit: 2435423 (Feb 24, 2026)

Duel Arena Minimap Shows Black Holes

Symptom: Minimap shows duel arenas as black holes, unusable in arena area Cause: Arena/lobby/hospital floor meshes had layer 0 disabled Solution: Update to latest code (commit 2435423 fixed this) Technical Details:
  • Enabled layer 0 on arena/lobby/hospital floor meshes so minimap camera can render them
  • File: packages/shared/src/systems/client/DuelArenaVisualsSystem.ts
  • Commit: 2435423 (Feb 24, 2026)

Victory Emote Overridden by Combat Cleanup

Symptom: Winning agent’s wave emote is immediately overwritten by idle animation after duel victory Cause: Combat animation system’s stale idle resets override victory emote Solution: Update to latest code (commit 645137386 fixed this) Technical Details:
  • Delayed Victory Emote: Victory emote now delayed by 600ms after combat resolution
    • Allows all death/combat cleanup (emote resets, combat state teardown, scheduled animation resets) to finish first
    • Without delay, victory emote was immediately overwritten by stale idle resets from combat animation system
  • Emote Reset in stopCombat: Reset emote to idle when agents teleport out
    • Ensures wave animation stops when agents leave arena
    • Prevents emote from persisting after duel ends
  • Entity Data Sync: Set emote on server entity so future entity sync includes it
    • Ensures victory emote is part of entity state
    • Broadcasts to all clients via entityModified packet
  • File: packages/server/src/systems/StreamingDuelScheduler/managers/DuelOrchestrator.ts
  • Commit: 645137386 (Feb 25, 2026)

WebSocket Type Errors

Symptom: TypeScript errors about missing removeAllListeners and on methods on WebSocket connections Cause: Fastify websocket connections use ws library type, not browser WebSocket Solution: Update to latest code (commit efba5a0 fixed this) Technical Details:
  • Import proper WebSocket type from ws library: import type { WebSocket } from 'ws'
  • Fastify’s @fastify/websocket uses the ws library under the hood
  • Browser WebSocket type doesn’t have Node.js EventEmitter methods
  • File: packages/server/src/systems/ServerNetwork/index.ts
  • Commit: efba5a0 (Feb 26, 2026)

Asset-Forge TypeScript Strict Mode Errors

Symptom: TypeScript errors in asset-forge about implicit any types in traverse callbacks Cause: TypeScript strict mode requires explicit types for callback parameters Solution: Update to latest code (commits 82f97da, 42e52af fixed this) Technical Details:
  • Traverse Callbacks (commit 82f97da): Added type annotations for traverse callbacks
    • Example: (child: THREE.Object3D) => { ... } instead of (child) => { ... }
    • Required by TypeScript strict mode
  • Module Resolution (commit 42e52af): Updated to moduleResolution: "bundler"
    • Three.js WebGPU subpath requires bundler or node16 module resolution
    • Previous 'node' setting couldn’t resolve the exports map correctly
    • File: packages/asset-forge/tsconfig.json

Type Safety in Core Game Logic

Symptom: Explicit any types in core game logic causing type safety issues Cause: Legacy code with untyped variables Solution: Update to latest code (commit d911359 fixed this) Technical Details:
  • tile-movement.ts: Removed 13 any casts by properly typing BuildingCollisionService and ICollisionMatrix method calls
  • proxy-routes.ts: Replaced any with proper types:
    • Error handlers: unknown for caught errors
    • WebSocket message handlers: Buffer | string for message data
    • Error events: Error type
  • ClientGraphics.ts: Added cast for setupGPUCompute after WebGPU verification
    • WebGPU is now required, so cast is safe after verification check
  • Remaining any types (acceptable):
    • TSL shader code (ProceduralGrass.ts) - @types/three limitation
    • Browser polyfills (polyfills.ts) - intentional mock implementations
    • Test files - acceptable for test fixtures
  • Commit: d911359 (Feb 26, 2026)

Duplicate Teleport VFX

Symptom: Three teleport effects play when agents exit duel arena (should only be one) Cause: Race condition between clearDuelFlagsForCycle() and ejectNonDuelingPlayersFromCombatArenas() Solution: Update to latest code (commit 7bf0e14 fixed this) Technical Details:
  • Removed premature clearDuelFlagsForCycle() in endCycle()
  • Flags now stay true until cleanupAfterDuel() completes teleports via microtask
  • Prevents DuelSystem from seeing agents with inStreamingDuel=false still in arena
  • suppressEffect flag now forwarded through ServerNetwork → ClientNetwork → VFX system
  • Mid-fight proximity corrections suppressed, arena exit effects visible
  • Removed duplicate PLAYER_TELEPORTED emit from PlayerRemote.modify() and local player path
  • File: packages/server/src/systems/StreamingDuelScheduler/index.ts
  • Commit: 7bf0e14 (Feb 25, 2026)

Teleport Beam Clipping Through Floor

Symptom: Teleport beam base penetrates through floor instead of emerging from rune circle Cause: No fade at beam base, full opacity from bottom to top Solution: Update to latest code (commit ceb8909 fixed this) Technical Details:
  • Added bottomFade in TSL beam shader
  • Soft fade at beam base: sub(1.0, max(sub(1.0, mul(yNorm, 2.0)), 0.0))
  • Beam now emerges from rune circle smoothly
  • File: packages/shared/src/systems/client/ClientTeleportEffectsSystem.ts
  • Commit: ceb8909 (Feb 25, 2026)

Streaming Disconnects After 2 Minutes

Symptom: RTMP stream disconnects or restarts every ~2 minutes Cause: CDP stall threshold too aggressive (2 intervals = 60s) Solution: Update to latest code (commit 14a1e1b fixed this) Technical Details:
  • CDP Stall Threshold: Increased from 2 → 4 intervals (120s) to reduce false restarts
  • Soft CDP Recovery: Restart screencast without browser/FFmpeg teardown
    • No stream gap during recovery
    • Preserves browser state
  • FFmpeg Restart Attempts: Increased from 5 → 8 max attempts
  • Recovery Counter Reset: resetRestartAttempts() for successful recovery
  • Capture Recovery Failures: Increased default from 2 → 4 max failures
  • File: packages/server/src/streaming/
  • Commit: 14a1e1b (Feb 25, 2026)

WebGPU Renderer Fails to Initialize

Symptom: WebGPU renderer initialization fails with “Required limits not supported” error Cause: GPU doesn’t support maxTextureArrayLayers: 2048 Solution: Update to latest code (commit 14a1e1b fixed this) Technical Details:
  • Best-Effort Limits: Renderer now tries maxTextureArrayLayers: 2048 first
    • Retries with default limits if GPU rejects
    • Always WebGPU, never WebGL fallback
    • Prevents renderer init failures on GPUs with lower limits
  • Graceful Degradation: Falls back to GPU’s supported limits automatically
  • No WebGL Fallback: Ensures consistent rendering pipeline (WebGPU only)
  • File: packages/shared/src/utils/rendering/RendererFactory.ts
  • Commit: 14a1e1b (Feb 25, 2026)

NPM 403 Forbidden Errors in CI

Symptom: bun install fails in GitHub Actions with npm 403 Forbidden errors Cause: npm rate-limits GitHub Actions IP ranges Solution: Update to latest code (commits 7c9ff6c, 08aa151 fixed this) Technical Details:
  • Retry with backoff: up to 5 attempts with increasing delays (15s, 30s, 45s, 60s, 75s)
  • Use --frozen-lockfile in all workflows to prevent fresh package resolution
  • Ensures bun uses only committed lockfile
  • Files: .github/workflows/*.yml
  • Commits: 7c9ff6c, 08aa151 (Feb 25, 2026)

Tauri macOS Build Fails with Empty Certificate

Symptom: Tauri macOS builds fail with SecKeychainItemImport error even for non-release builds Cause: Tauri bundler attempts code signing whenever APPLE_CERTIFICATE env var exists, even if empty Solution: Update to latest code (commit 15250d2 fixed this) Technical Details:
  • Build workflow split into Unsigned and Release variants
  • Signing env vars only present during actual releases
  • Non-release builds no longer set APPLE_CERTIFICATE=''
  • macOS unsigned builds use --bundles app to skip DMG creation
  • iOS builds are release-only (unsigned iOS always fails)
  • Windows builds have retry logic for transient NPM registry errors
  • File: .github/workflows/build-app.yml
  • Commit: 15250d2 (Feb 25, 2026)

Getting Help

  1. Check GitHub Issues
  2. Search existing discussions
  3. Open a new issue with:
    • Error message
    • Steps to reproduce
    • Environment details (OS, Node version, Bun version)