GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix: resolve self-hosting issues on Ubuntu without Docker by wav-piyush · Pull Request #7917 · simstudioai/sim

Conversation

@wav-piyush

@wav-piyush wav-piyush commented Sep 17, 2026

Copy link
Copy Markdown

Overview

Fixes multiple issues reported in #6158 that break self-hosting Sim on Ubuntu 24.04 without Docker. The three bugs addressed are: silent failure when database migrations haven't been run, dev server killed by OTel export timeouts, and desktop build failure due to cross-device rename.

Changes

1. Better error handling for missing database migrations

File: apps/sim/lib/auth/anonymous.ts

When DISABLE_AUTH=true and the database has no tables (migrations not run), ensureAnonymousUserExists() would fail with a Postgres 42P01 (undefined_table) error. This error was caught by withRouteHandler and returned as a generic "Internal server error" to the client, leaving users with no guidance.

Fix: Added isMissingTableError() helper that detects Postgres error code 42P01 at any nesting level (Drizzle wraps it in error.cause). When detected, throws a clear error: "Database tables not found. Run database migrations before starting the app: bun run db:migrate". This message appears in server logs for developers to see, while the client still receives a generic error (no internal details exposed to end users).

2. Prevent OTel timeout from killing dev server

Files: apps/sim/instrumentation-node.ts, apps/sim/telemetry.config.ts, apps/sim/.env.example

The OpenTelemetry SDK tries to export telemetry data to telemetry.simstudio.ai. When this endpoint is unreachable (firewall, network issues, self-hosted environments), the export hangs for 30 seconds, the event loop drains, and the process exits. Additionally, SIGTERM handlers used process.on() instead of process.once(), causing duplicate handler execution during Next.js HMR reloads (visible as 3x "PostHog client shut down successfully" log lines).

Fixes:

  • Added DISABLE_TELEMETRY=1 env var that skips all OTel initialization before any dynamic imports (zero overhead)
  • Reduced exportTimeoutMillis from 30s to 10s for faster failure when endpoint is unreachable
  • Wrapped sdk.shutdown() in Promise.race with a 5s timeout — hard ceiling so shutdown can never block process exit
  • Changed all 4 SIGTERM/SIGINT handlers from process.on() to process.once() to prevent duplicate execution

3. Fix desktop EXDEV cross-device rename

File: apps/desktop/scripts/ensure-pty-prebuilds.ts

The desktop build script downloads a prebuilt binary to /tmp (tmpfs) and then calls renameSync() to move it to the project directory under /home (ext4). On Linux, rename(2) fails with EXDEV: cross-device link not permitted when source and destination are on different filesystems.

Fix: Replaced renameSync() with cpSync(..., { recursive: true, force: true }) which works across filesystem boundaries. The staging directory is still cleaned up in the finally block.

Related

  • Closes Self-hosting on Ubuntu 24.04 without Docker is broken — SIGTERM kills dev server, build fails, no DB seed #6158

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
wav-piyush added 5 commits September 17, 2026 11:16
@wav-piyush
fix: catch missing DB tables error with clear message in anonymous auth
4eee650
Detect Postgres error code 42P01 (undefined_table) in
ensureAnonymousUserExists() and throw an actionable error message
instead of a generic internal server error. This helps developers
quickly identify that database migrations need to be run.
@wav-piyush
fix: prevent OTel timeout from killing dev server
c155996
- Add DISABLE_TELEMETRY env var to skip all OTel initialization
- Reduce export timeout from 30s to 10s for faster failure
- Wrap sdk.shutdown() with 5s timeout to prevent blocking exit
- Change process.on to process.once for SIGTERM/SIGINT handlers
  to prevent duplicate execution during HMR reloads
@wav-piyush
fix: reduce OTel batch export timeout from 30s to 10s
393ef65
Match the default config in instrumentation-node.ts to prevent
long shutdown hangs when the telemetry endpoint is unreachable.
@wav-piyush
docs: add DISABLE_TELEMETRY env var to .env.example
90753e4
Document the new env var that disables all OpenTelemetry collection,
preventing export timeouts when the telemetry endpoint is unreachable.
@wav-piyush
fix: replace renameSync with cpSync to prevent EXDEV on Ubuntu
d131229
renameSync fails with 'EXDEV: cross-device link not permitted' when
moving files from /tmp (tmpfs) to the project directory (ext4) on
Ubuntu. Use cpSync with recursive and force options instead, which
works across filesystem boundaries.
@vercel

vercel Bot commented Sep 17, 2026

Copy link
Copy Markdown

@Arav-Menon is attempting to deploy a commit to the Sim Team on Vercel.

A member of the Team first needs to authorize it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@greptile-apps

greptile-apps Bot commented Sep 17, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 2/5

The PR is not yet safe to merge because repeated instrumentation registration still duplicates shutdown handlers, successful shutdown can be delayed by its own timeout timer, and deeply wrapped missing-table errors remain undetected.

Findings

  1. P1 Handlers Still Accumulate ▶
  2. P1 Timeout Delays Successful Shutdown ▶
  3. P1 Nested Errors Remain Undetected ▶
  4. P2 Shared Delay Helper Bypassed ▶
  5. P2 Copy Can Leave Partial Install ▶

Summary

This PR improves Ubuntu self-hosting diagnostics, adds an OpenTelemetry opt-out and shorter export timeout, adjusts shutdown signal handling, and replaces a cross-filesystem desktop prebuild rename with a recursive copy.

  • Adds actionable missing-migration guidance for anonymous authentication.
  • Adds DISABLE_TELEMETRY=1 and shorter OTel export timeouts.
  • Adds a bounded OTel shutdown race and changes signal listeners to one-shot handlers.
  • Makes desktop prebuild installation work across filesystems.
  • The new signal handling still accumulates handlers during repeated registration, the timeout leaves a live timer, and missing-table detection does not traverse all supported error wrappers.

Reviews (1) · Last reviewed commit: "fix: replace renameSync with cpSync to p..."

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot]
greptile-apps Bot reviewed Sep 17, 2026
View reviewed changes
Comment thread apps/sim/instrumentation-node.ts
Comment on lines +377 to +378
process.once('SIGTERM', shutdownOtel)
process.once('SIGINT', shutdownOtel)

@greptile-apps greptile-apps Bot Sep 17, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Handlers Still Accumulate

process.once() removes a listener only after it fires; it does not deduplicate listeners added by repeated instrumentation registration during HMR. Each reload therefore adds another OTel shutdown closure here and another PostHog closure at lines 409–410. All accumulated handlers run on the next signal, so duplicate shutdowns still occur. Make initialization idempotent or explicitly replace the previous listeners.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread apps/sim/instrumentation-node.ts
Comment on lines +367 to +370
const timeoutPromise = new Promise<void>((_, reject) =>
setTimeout(() => reject(new Error('OTel shutdown timed out')), 5000)
)
await Promise.race([shutdownPromise, timeoutPromise])

@greptile-apps greptile-apps Bot Sep 17, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Timeout Delays Successful Shutdown

When sdk.shutdown() finishes first, this five-second timer is neither cleared nor unreferenced. The installed SIGTERM and SIGINT listeners disable Node's default signal exit, so the pending timer keeps the event loop alive for the rest of those five seconds even after shutdown succeeds. Store and clear the timer in a finally block, or otherwise prevent it from keeping the process alive.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread apps/sim/lib/auth/anonymous.ts
Comment on lines +18 to +21
const innerCode = (cause as Record<string, unknown>).code
if (innerCode === '42P01') return true
}
}

@greptile-apps greptile-apps Bot Sep 17, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Nested Errors Remain Undetected

This checks only the top-level error and its immediate cause, although the repository's PostgreSQL error handling supports deeper cause chains. If Drizzle wraps 42P01 beneath two causes, this helper misses it and self-hosters still get the generic failure instead of the migration guidance. Reuse getPostgresErrorCode from @sim/utils, which already walks nested causes safely.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread apps/sim/instrumentation-node.ts
Comment on lines +367 to +369
const timeoutPromise = new Promise<void>((_, reject) =>
setTimeout(() => reject(new Error('OTel shutdown timed out')), 5000)
)

@greptile-apps greptile-apps Bot Sep 17, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Shared Delay Helper Bypassed

This change constructs a delay with new Promise and setTimeout, violating the repository directive to use the shared sleep(ms) helper from @sim/utils/helpers instead of inline timeout promises. This repository requirement must be satisfied before merging.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread apps/desktop/scripts/ensure-pty-prebuilds.ts
Comment on lines 105 to +106
rmSync(target, { recursive: true, force: true })
renameSync(join(staging, 'package'), target)
cpSync(join(staging, 'package'), target, { recursive: true, force: true })

@greptile-apps greptile-apps Bot Sep 17, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Copy Can Leave Partial Install

The script now deletes the working target and copies directly into that live directory, so interruption, disk exhaustion, or a copy error can leave a partial installation. A later run checks only whether pty.node exists, so a torn copy containing that file can be treated as valid and reused. Copy into a temporary directory on the destination filesystem first, then atomically rename it into place.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@greptile-apps greptile-apps[bot] greptile-apps[bot] left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Self-hosting on Ubuntu 24.04 without Docker is broken — SIGTERM kills dev server, build fails, no DB seed

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@wav-piyush
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.