hcengineering/platform · error

Internal Server Error

Error message

Internal Server Error

What it means

The route wrapper around handleBackup catches any unhandled promise rejection and responds HTTP 500 'Internal Server Error'. It fires when code after authentication/authorization fails — e.g. createStorageBackupStorage throwing, storage.statInfo/load raising, gunzip failing on corrupt backup.json.gz, or the storage stream erroring mid-pipe.

Source

Thrown at services/backup/backup-api-pod/src/server.ts:359

          return
        }
      }

      // Forward the R2 object with original headers
      // return new Response(fileInfo.body, {
      //   headers: responseHeaders
      // })
      res.status(200).set(responseHeaders)
      ;(await storage.load(file)).pipe(res)
      return
    }
    res.status(404).end('Not found')
  }

  app.get('/api/backup/:workspace/:file(*)', (req, res) => {
    void handleBackup(req, res).catch((err) => {
      console.error('request error', err)
      res.status(500).end('Internal Server Error')
    })
  })

  app.get('/', (req, res) => {
    res.send(`Huly&reg; Backup&trade; <a href="https://huly.io">https://huly.io</a>
      &copy; 2024 <a href="https://hulylabs.com">Huly Labs</a>`)
  })

  const sendErrorToAnalytics = (err: any): boolean => {
    const ignoreMessages = [
      'Unexpected end of form', // happens when the client closes the connection before the upload is complete
      'Premature close', // happens when the client closes the connection before the upload is complete
      'File too large' // happens when the file exceeds the limit set by express-fileupload
    ]

    return !ignoreMessages.includes(err.message)
  }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Check the backup pod logs for the 'request error' entry to identify the underlying exception
  2. Validate storage env config (bucket/credentials) used by storageConfigFromEnv
  3. Inspect/repair the workspace's backup.json.gz if gunzip errors appear in logs
  4. Retry after confirming the object-storage backend is healthy

Example fix

// client-side
// before
const res = await fetch(url)
const body = await res.text()
// after
const res = await fetch(url)
if (res.status === 500) throw new Error('backup API internal error, check server logs')
const body = await res.text()
Defensive patterns

Strategy: try-catch

Validate before calling

// verify storage config before starting downloads
const cfg = storageConfigFromEnv(config.Storage)
if (!cfg.storages?.length) throw new Error('No storage configured')

Type guard

function isStorageError(err: unknown): boolean {
  return typeof err === 'object' && err !== null && /storage|gunzip|ECONN|bucket/i.test((err as any).message ?? '')
}

Try / catch

const res = await fetch(url, { headers })
if (res.status === 500) {
  const body = await res.text()
  throw new Error(`Backup API failed (500). Inspect server 'request error' logs: ${body}`)
}

Prevention

When it happens

Trigger: Storage adapter misconfiguration (bad bucket config from env), corrupt gzip metadata files, storage backend outages, or any exception thrown outside the inner try/catch blocks of handleBackup.

Common situations: Huly operators see this when object-storage credentials/config are wrong (storageConfigFromEnv failing), during storage-backend incidents, or when a backup.json.gz in the bucket is truncated/corrupt.

Understand the failure class

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/ccde4db8e1e11b73. Report an issue: GitHub.