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 Ruff playground's fetchPlayground when the backend answers a non-2xx HTTP status. Playgrounds are persisted on a Cloudflare worker (https://api.astral-1ad.workers.dev in production, http://localhost:8787 in local dev), so this error means the request reached a server but the server refused or failed it (note: response.json() is only called on success).
Source
Thrown at playground/ruff/src/Editor/api.ts:16
const API_URL = import.meta.env.PROD
? "https://api.astral-1ad.workers.dev"
: "http://localhost:8787";
export type Playground = {
pythonSource: string;
settingsSource: 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}`);
}
return await response.text();
}
View on GitHub (pinned to 672bb4edf0)
Solutions
- Verify the playground ID in the URL is complete and unmodified
- Confirm the worker deployment is healthy (open the API URL directly and check for a sane response) and retry
- Ask the sender to re-share the snippet; the stored entry may have expired or never been saved
- In local dev, ensure the API worker (localhost:8787) is running before the web dev server calls it
Example fix
// before
const playground = await fetchPlayground(id); // may throw on 404/5xx
// after
try {
const playground = await fetchPlayground(id);
} catch (error) {
console.error((error as Error).message);
// fall back to the default playground content
} 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).pythonSource === 'string' &&
typeof (v as Playground).settingsSource === 'string'
);
} Try / catch
try {
const playground = await fetchPlayground(id);
if (!playground) return defaults();
return playground;
} catch (error) {
console.error(`Could not load shared playground: ${(error as Error).message}`);
return defaults();
} Prevention
- Treat playground IDs as opaque; never construct or edit them by hand
- Always render a default playground when loading fails instead of crashing the editor
- In dev, health-check localhost:8787 before enabling share-button features
When it happens
Trigger: GET `${API_URL}/${encodeURIComponent(id)}` returning 404 for an unknown, mistyped, or expired playground ID, or 5xx when the worker itself is failing.
Common situations: Opening an old share link whose snippet expired server-side; hand-editing or truncating the ID in a URL; a partially deployed or broken worker.
Related errors
- Failed to save playground: ${response.status}
- Failed to fetch playground ${id}: ${response.status}
- Failed to save playground: ${response.status}
- Git fetch of commit {} failed: {}
- Git clone failed: {}
AI-assisted analysis of astral-sh/ruff@672bb4edf0 (2026-08-16).
Data as JSON: /api/errors/a3dcb3f0697e69a6.
Report an issue: GitHub.