astral-sh/ruff · error · Error

Failed to fetch playground ${id}: ${response.status}

Error message

Failed to fetch playground ${id}: ${response.status}

What it means

Thrown by the ty playground's fetchPlayground when the backend answers a non-2xx status. The ty playground stores multi-file projects (a files map plus the current file name) on the share API worker, and this error means the server was reached but refused or failed the lookup.

Source

Thrown at playground/ty/src/Editor/api.ts:18

const API_URL = import.meta.env.PROD
  ? "https://api.astral-1ad.workers.dev"
  : "http://localhost:8787";

export type Playground = {
  files: { [name: string]: string };
  /// the name of the current file
  current: string;
};

/**
 * Fetch a playground by ID.
 */
export async function fetchPlayground(id: string): Promise<Playground | null> {
  const response = await fetch(`${API_URL}/${encodeURIComponent(id)}`);

  if (!response.ok) {
    throw new Error(`Failed to fetch playground ${id}: ${response.status}`);
  }

  return await response.json();
}

/**
 * Save a playground and return its ID.
 */
export async function savePlayground(playground: Playground): Promise<string> {
  const response = await fetch(API_URL, {
    method: "POST",
    body: JSON.stringify(playground),
  });

  if (!response.ok) {
    throw new Error(`Failed to save playground: ${response.status}`);
  }

View on GitHub (pinned to 672bb4edf0)

Solutions

  1. Verify the ID in the URL is complete and unmodified
  2. Confirm the API worker deployment is healthy, then retry the load
  3. Ask the sender to re-share the playground if the stored entry expired
  4. In local dev, start the worker on localhost:8787 before loading shared links

Example fix

// before
const playground = await fetchPlayground(id);

// after
try {
  const playground = await fetchPlayground(id);
} catch (error) {
  console.error((error as Error).message);
  // fall back to the default playground files
}
Defensive patterns

Strategy: try-catch

Validate before calling

const ID_RE = /^[A-Za-z0-9_-]{4,}$/;
if (!ID_RE.test(id)) {
  throw new RangeError(`Invalid playground id: ${id}`);
}

Type guard

function isPlayground(v: unknown): v is Playground {
  return (
    typeof v === 'object' && v !== null &&
    typeof (v as Playground).current === 'string' &&
    typeof (v as Playground).files === 'object' &&
    (v as Playground).files !== null &&
    Object.values((v as Playground).files).every((f) => typeof f === 'string')
  );
}

Try / catch

try {
  const playground = await fetchPlayground(id);
  if (!isPlayground(playground)) return defaults();
  return playground;
} catch (error) {
  console.error(`Could not load shared playground: ${(error as Error).message}`);
  return defaults();
}

Prevention

When it happens

Trigger: GET `${API_URL}/${encodeURIComponent(id)}` returning 404 for an unknown, mistyped, or expired playground ID, or 5xx from a failing worker.

Common situations: Opening stale share links whose snippet expired; manually editing the ID in the URL; worker outage or partial deployment.

Related errors


AI-assisted analysis of astral-sh/ruff@672bb4edf0 (2026-08-16). Data as JSON: /api/errors/41c9304cb08ef1a3. Report an issue: GitHub.