TryGhost/Ghost · error · HostLimitError
A hosting plan limit was reached or exceeded.
Error message
A hosting plan limit was reached or exceeded.
What it means
HostLimitError, thrown by handleResponse when errors[0].type === 'HostLimitError'. It indicates an enforced hosting-plan limit was reached — member count, staff/user count, or another metered cap on Ghost(Pro) (or a host implementing the same error type). The specific limit is in error.data.
Source
Thrown at apps/admin-x-framework/src/utils/api/handle-response.ts:35
} else if (!response.ok) {
if (!response.headers.get('content-type')?.includes('json')) {
throw new APIError(response, await response.text());
}
const data = await response.json() as ErrorResponse;
if (response.status === 403 && data.errors?.[0]?.message === 'Authorization failed') {
throw new UnauthorizedError(response, data);
} else if (data.errors?.[0]?.type === 'VersionMismatchError') {
throw new VersionMismatchError(response, data);
} else if (data.errors?.[0]?.type === 'ValidationError') {
throw new ValidationError(response, data);
} else if (data.errors?.[0]?.type === 'NoPermissionError') {
throw new ValidationError(response, data);
} else if (data.errors?.[0]?.type === 'ThemeValidationError') {
throw new ThemeValidationError(response, data);
} else if (data.errors?.[0]?.type === 'HostLimitError') {
throw new HostLimitError(response, data);
} else if (data.errors?.[0]?.type === 'EmailError') {
throw new EmailError(response, data);
} else {
throw new JSONError(response, data);
}
} else if (response.status === 204) {
return;
} else if (response.headers.get('content-type')?.includes('text/csv')) {
return await response.text();
} else {
return await response.json();
}
};
export default handleResponse;
View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Read error.data.errors[0].message/context to see which limit was hit and by how much.
- Upgrade the hosting plan to raise the affected cap, or reduce usage (remove inactive members/staff) below the limit.
- For member imports, split or filter the import so it stays within the remaining quota.
Defensive patterns
Strategy: type-guard
Type guard
import {HostLimitError} from '@tryghost/admin-x-framework/utils/errors';
function isHostLimit(e: unknown): e is HostLimitError {
return e instanceof HostLimitError;
} Try / catch
import {HostLimitError} from '@tryghost/admin-x-framework/utils/errors';
try {
await api.members.upload(csvFile);
} catch (e) {
if (e instanceof HostLimitError) {
notify('Plan limit reached. Upgrade your plan or remove unused members.');
// e.data?.errors?.[0]?.message has the specific cap
} else throw e;
} Prevention
- Check remaining quota before bulk member imports.
- Surface the specific limit from error.data so the user knows whether it's members, staff, etc.
- Offer an in-app upgrade path when the limit is a hosting-plan cap.
When it happens
Trigger: Performing an action that would exceed the plan's cap: importing members past the plan limit; inviting staff beyond the allowed seats; an operation blocked by the hosting provider's quota enforcement.
Common situations: Ghost(Pro) Starter/Basic plans with member or staff limits; an import that would push members over the tier cap; a host-side restriction not visible in self-host Ghost.
Related errors
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/a2c820317fbfc1c9.
Report an issue: GitHub.