heygen-com/hyperframes · error

Failed to publish project

Error message

Failed to publish project

What it means

publishProjectArchiveDirect: the direct POST to /v1/hyperframes/projects/publish returned a Response, but either !response.ok (HTTP 4xx/5xx) OR parsePublishedProjectResponse returned null (payload missing required fields: project_id, title, url, file_count, or claim_token for anonymous publishes). readErrorMessage extracts the server's JSON message field or response body, falling back to the literal 'Failed to publish project'. This is a server-level error response, distinct from the transport-level [255].

Source

Thrown at packages/cli/src/utils/publishProject.ts:576

    new File([archiveArrayBuffer(archive)], `${title}.zip`, { type: PUBLISH_CONTENT_TYPE }),
  );
  const headers: Record<string, string> = { ...authHeaders };

  const response = await fetchForPublish(
    `${apiBaseUrl}/v1/hyperframes/projects/publish`,
    () => ({
      method: "POST",
      body,
      headers,
      signal: AbortSignal.timeout(uploadTimeoutMs(archive.buffer.byteLength)),
    }),
    "Failed to publish project",
  );

  const payload = await readJson(response);
  const publishedProject = parsePublishedProjectResponse(payload);
  if (!response.ok || !publishedProject) {
    throw new Error(await readErrorMessage(response, "Failed to publish project"));
  }

  return publishedProject;
}

async function uploadArchiveToPresignedUrl(
  stagedUpload: StagedUploadResponse,
  archive: PublishArchiveResult,
): Promise<void> {
  const presignedUrlTtlMs = stagedUpload.expiresInSeconds * 1000 - PUBLISH_METADATA_TIMEOUT_MS;
  const s3Response = await fetchForPublish(
    stagedUpload.uploadUrl,
    () => ({
      method: "PUT",
      body: new Blob([archiveArrayBuffer(archive)], { type: stagedUpload.contentType }),
      headers: stagedUpload.uploadHeaders,
      signal: AbortSignal.timeout(
        Math.min(uploadTimeoutMs(archive.buffer.byteLength), presignedUrlTtlMs),

View on GitHub (pinned to c2996c8626)

Solutions

  1. Read the full error message — it includes the server's response body or JSON message field.
  2. For 401/403, refresh credentials (re-authenticate) and retry.
  3. For 400, address the specific validation error (title characters, archive size, etc.).
  4. For 5xx, retry after a short wait — transient server errors are common.
  5. For malformed-response (no specific HTTP error), capture the raw response body and report it as a server bug.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return await publishProjectArchive(projectDir, opts);
} catch (err) {
  if (err instanceof Error && /Failed to publish project/.test(err.message)) {
    // err.message carries the server's response text — log and surface to user
    console.error('Publish rejected by server:', err.message);
    // for 401/403, prompt re-auth; for 5xx, retry after backoff
  } else throw err;
}

Prevention

When it happens

Trigger: The API rejected the publish: authentication failed (401), rate limited (429), validation error (400 — e.g. bad title), server error (500), or the response JSON was present but malformed/incomplete (missing project_id/url/etc.). Also when an anonymous publish response omitted claim_token (which parsePublishedProjectResponse treats as invalid).

Common situations: Expired or invalid auth credentials; publishing a project that exceeds size/feature limits; a title with disallowed characters; the API is temporarily returning 500s; a partial service outage where the metadata endpoint is up but the publish backend is degraded; an anonymous publish where the server bug omitted claim_token.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/fc0dfa079db13dad. Report an issue: GitHub.