vercel/hyper · warning · Error

Malformed server response: release name is missing.

Error message

Malformed server response: release name is missing.

What it means

Thrown by Hyper's Linux AutoUpdater (app/auto-updater-linux.ts) after it fetches the configured update feed and parses the response as JSON. The feed contract requires an object with {name, notes, pub_date}, and `name` is the only mandatory field because it is used to construct the release download URL. If the parsed body has no `name` (or `name` is falsy/undefined), the updater cannot proceed and throws. The throw happens inside a resolved promise and is funneled to `emitError`, so it surfaces as an `'error'` event on the autoUpdater EventEmitter rather than a synchronous exception.

Source

Thrown at app/auto-updater-linux.ts:33

    this.updateURL = options.url;
  }

  checkForUpdates() {
    if (!this.updateURL) {
      return this.emitError('Update URL is not set');
    }
    this.emit('checking-for-update');

    fetch(this.updateURL)
      .then((res) => {
        if (res.status === 204) {
          this.emit('update-not-available');
          return;
        }
        return res.json().then(({name, notes, pub_date}: {name: string; notes: string; pub_date: string}) => {
          // Only name is mandatory, needed to construct release URL.
          if (!name) {
            throw new Error('Malformed server response: release name is missing.');
          }
          const date = pub_date ? new Date(pub_date) : new Date();
          this.emit('update-available', {}, notes, name, date);
        });
      })
      .catch(this.emitError.bind(this));
  }

  emitError(error: string | Error) {
    if (typeof error === 'string') {
      error = new Error(error);
    }
    this.emit('error', error);
  }
}

const autoUpdaterLinux = new AutoUpdater();

View on GitHub (pinned to da0c401d7f)

Solutions

  1. curl -i the exact updateURL from setFeedURL and confirm the JSON body contains a non-empty `name` field; the contract is {name: string, notes?: string, pub_date?: string}.
  2. If you control the update server, ensure every non-204 release response includes `name` (typically the release tag/version string).
  3. If using electron-builder, point the feed URL at the JSON it generates (or use electron-updater) instead of a hand-rolled endpoint that omits `name`.
  4. Register an `autoUpdater.on('error', err => ...)` listener so a malformed feed degrades gracefully instead of surfacing as an unhandled EventEmitter error (Node throws on unhandled 'error' events).
  5. Verify no proxy/CDN is rewriting the response body; check the `content-type` and raw bytes, not just the status code.

Example fix

// before
autoUpdaterLinux.setFeedURL({url: 'https://example.com/releases/latest'});
autoUpdaterLinux.checkForUpdates();
// server returns {} or {notes, pub_date} with no name -> 'Malformed server response: release name is missing.'

// after — fix the feed to include name AND guard the consumer
// server-side: respond with {"name":"v3.1.0","notes":"...","pub_date":"2026-08-12T00:00:00Z"}
import autoUpdaterLinux from './app/auto-updater-linux';
autoUpdaterLinux.setFeedURL({url: 'https://example.com/releases/latest'});
autoUpdaterLinux.on('error', (err) => {
  // graceful degradation — never let an EventEmitter 'error' go unhandled
  console.warn('Update check failed:', err.message);
});
autoUpdaterLinux.checkForUpdates();
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight the feed before handing the URL to the AutoUpdater so a malformed
// server never reaches the throw site. Run once at app start or on URL change.
import fetch from 'electron-fetch';

async function assertFeedShape(url: string): Promise<void> {
  const res = await fetch(url);
  if (res.status === 204) return; // update-not-available, no body needed
  if (!res.ok) throw new Error(`Feed HTTP ${res.status}`);
  const body = await res.json() as unknown;
  if (
    typeof body !== 'object' ||
    body === null ||
    typeof (body as { name?: unknown }).name !== 'string' ||
    (body as { name: string }).name.length === 0
  ) {
    throw new Error(`Feed at ${url} is missing a non-empty \`name\` field`);
  }
}

// usage
await assertFeedShape(autoUpdaterLinux.getFeedURL());
autoUpdaterLinux.checkForUpdates();

Type guard

// Narrow the parsed feed before touching required fields.
import type { ReleaseFeed } from './release-feed'; // { name: string; notes?: string; pub_date?: string }

function isReleaseFeed(v: unknown): v is ReleaseFeed {
  if (typeof v !== 'object' || v === null) return false;
  const name = (v as { name?: unknown }).name;
  if (typeof name !== 'string' || name.length === 0) return false;
  return true;
}

const body: unknown = await res.json();
if (!isReleaseFeed(body)) {
  throw new Error('Malformed server response: release name is missing.');
}
// body.name is now string

Try / catch

// AutoUpdater is an EventEmitter; the throw is converted to an 'error' event.
// Always attach a listener BEFORE checkForUpdates — Node throws on unhandled 'error'.
import autoUpdaterLinux from './app/auto-updater-linux';

autoUpdaterLinux.once('error', (err: Error) => {
  if (/release name is missing/i.test(err.message)) {
    // Known shape: feed contract violation. Degrade silently, schedule retry.
    console.warn('Update feed malformed, skipping this check:', err.message);
    return;
  }
  // Unknown cause — surface to app-level error reporting.
  throw err;
});
autoUpdaterLinux.on('update-available', (_e, notes, name, date) => {
  /* ... */
});
autoUpdaterLinux.checkForUpdates();

Prevention

When it happens

Trigger: Calling `autoUpdaterLinux.checkForUpdates()` after `setFeedURL({url})` where `url` resolves to a 200/2xx response whose JSON body lacks a `name` key (e.g. `{}`, `{notes, pub_date}` without name, a GitHub API rate-limit JSON, a redirect/captive-portal JSON page, or any non-update JSON the server happens to return). A 204 short-circuits to `update-not-available` before this check, so the response must be non-204 with a JSON content-type that parses.

Common situations: Update URL misconfigured to point at a wrong endpoint (HTML landing page whose JSON parse yields empty object, GitHub API release JSON with `tag_name`/`name` mismatch, electron-builder's `latest.yml` served raw as YAML-in-JSON, proxy replacing the body with a block page that still deserializes, CDN serving a stale/malformed manifest after a botched release publish, or a v1/v2 feed schema change that renamed `name` to `version`).

Understand the failure class


AI-assisted analysis of vercel/hyper@da0c401d7f (2026-08-12). Data as JSON: /api/errors/28d97cf20f856b3f. Report an issue: GitHub.