Error Handling
The HiveForge SDK uses a hierarchy of error classes to help you handle different failure modes. All errors extend the standard Error class and include machine-readable codes for programmatic handling.
Error Classes
HiveForgeError
The base error class for all HiveForge API errors. Thrown by the core client when API requests fail.
import { HiveForgeError } from '@producthacker/hiveforge-sdk';
try {
await hiveforge.initialize();
} catch (error) {
if (error instanceof HiveForgeError) {
console.error('Message:', error.message);
console.error('Code:', error.code); // e.g., 'invalid_credentials'
console.error('Status:', error.status); // HTTP status code, e.g., 401
}
}Properties:
| Property | Type | Description |
|---|---|---|
message | string | Human-readable error message |
code | string | undefined | Machine-readable error code |
status | number | undefined | HTTP status code from the API |
AIProxyException
Thrown by AI proxy methods (hiveforge.ai.*). Includes quota-specific properties.
import { AIProxyException } from '@producthacker/hiveforge-sdk';
try {
const response = await hiveforge.ai.complete({
messages: [{ role: 'user', content: 'Hello!' }],
});
} catch (error) {
if (error instanceof AIProxyException) {
console.error('Code:', error.code);
console.error('Message:', error.message);
if (error.isQuotaExceeded) {
console.log('Quota exceeded!');
if (error.upgradeUrl) {
console.log('Upgrade at:', error.upgradeUrl);
}
}
}
}Properties:
| Property | Type | Description |
|---|---|---|
message | string | Error message |
code | string | Error code (e.g., 'quota_exceeded', 'ai_disabled') |
isQuotaExceeded | boolean | Whether this is a quota exceeded error |
upgradeUrl | string | undefined | URL to upgrade the subscription |
details | AIProxyError | Full error details from the API |
AIProxyError details object:
| Field | Type | Description |
|---|---|---|
error | string | Error type |
code | string | Error code |
message | string | Error message |
upgrade_url | string | Optional upgrade URL |
quota_exceeded | boolean | Whether quota was exceeded |
BillingProxyException
Thrown by billing proxy methods (hiveforge.billing.*).
import { BillingProxyException } from '@producthacker/hiveforge-sdk';
try {
const checkout = await hiveforge.billing.createCheckout({
priceId: 'price_1N2b3c4D5e6F7g8H9i0J',
customerEmail: 'jane@example.com',
successUrl: '/success',
cancelUrl: '/cancel',
});
} catch (error) {
if (error instanceof BillingProxyException) {
console.error(`Billing error [${error.code}]: ${error.message}`);
}
}Properties:
| Property | Type | Description |
|---|---|---|
message | string | Error message |
code | string | Error code (e.g., 'billing_disabled', 'stripe_error') |
details | BillingProxyError | Full error details |
EmailProxyException
Thrown by email proxy methods (hiveforge.email.*). Includes credit information for credit-related failures.
import { EmailProxyException } from '@producthacker/hiveforge-sdk';
try {
await hiveforge.email.send({
to: ['jane@example.com'],
subject: 'Hello',
html: '<p>Hi!</p>',
});
} catch (error) {
if (error instanceof EmailProxyException) {
console.error(`Email error [${error.code}]: ${error.message}`);
if (error.creditsRequired !== undefined) {
console.log(`Need ${error.creditsRequired} credits, have ${error.creditsAvailable}`);
}
}
}Properties:
| Property | Type | Description |
|---|---|---|
message | string | Error message |
code | string | Error code |
creditsRequired | number | undefined | Credits needed for the operation |
creditsAvailable | number | undefined | Credits currently available |
VectorProxyException
Thrown by vector proxy methods (hiveforge.vectors.*).
import { VectorProxyException } from '@producthacker/hiveforge-sdk';
try {
await hiveforge.vectors.search({ query: 'test' });
} catch (error) {
if (error instanceof VectorProxyException) {
console.error(`Vector error [${error.code}]: ${error.message}`);
if (error.creditsRequired !== undefined) {
console.log(`Need ${error.creditsRequired} credits, have ${error.creditsAvailable}`);
}
}
}Properties: Same as EmailProxyException.
WebhookProxyException
Thrown by webhook proxy methods (hiveforge.webhooks.*).
import { WebhookProxyException } from '@producthacker/hiveforge-sdk';
try {
await hiveforge.webhooks.send({
url: 'https://api.partner.com/webhooks',
payload: { event: 'test' },
});
} catch (error) {
if (error instanceof WebhookProxyException) {
console.error(`Webhook error [${error.code}]: ${error.message}`);
}
}Properties: Same as EmailProxyException.
Common Error Patterns
Handling Quota Exceeded
import { AIProxyException, HiveForgeError } from '@producthacker/hiveforge-sdk';
async function safeAIComplete(messages: Array<{ role: string; content: string }>) {
try {
return await hiveforge.ai.complete({
messages: messages as any,
});
} catch (error) {
if (error instanceof AIProxyException && error.isQuotaExceeded) {
// Option 1: Redirect to upgrade
if (typeof window !== 'undefined' && error.upgradeUrl) {
window.location.href = error.upgradeUrl;
return null;
}
// Option 2: Return a fallback response
return {
content: 'AI quota exceeded. Please upgrade your plan for continued access.',
model: 'fallback',
tokens_used: 0,
tokens_input: 0,
tokens_output: 0,
finish_reason: 'quota_exceeded',
};
}
throw error;
}
}Handling Authentication Errors
try {
await hiveforge.initialize();
} catch (error) {
if (error instanceof HiveForgeError) {
switch (error.status) {
case 401:
console.error('Invalid deployment credentials. Check HIVEFORGE_DEPLOYMENT_ID and HIVEFORGE_DEPLOYMENT_SECRET.');
break;
case 403:
console.error('Deployment is not authorized for this action.');
break;
case 404:
console.error('Deployment not found. Verify your deployment ID.');
break;
default:
console.error(`API error (${error.status}): ${error.message}`);
}
}
}Handling Credit Exhaustion Across Services
import {
EmailProxyException,
VectorProxyException,
WebhookProxyException,
} from '@producthacker/hiveforge-sdk';
type CreditError = EmailProxyException | VectorProxyException | WebhookProxyException;
function isCreditError(error: unknown): error is CreditError {
return (
(error instanceof EmailProxyException ||
error instanceof VectorProxyException ||
error instanceof WebhookProxyException) &&
error.creditsRequired !== undefined
);
}
async function withCreditCheck<T>(operation: () => Promise<T>): Promise<T> {
try {
return await operation();
} catch (error) {
if (isCreditError(error)) {
console.error(
`Insufficient credits: need ${error.creditsRequired}, have ${error.creditsAvailable}`
);
// Notify user or purchase more credits
throw new Error('Insufficient credits. Please purchase a credit pack to continue.');
}
throw error;
}
}
// Usage
const result = await withCreditCheck(() =>
hiveforge.email.send({
to: ['jane@example.com'],
subject: 'Hello',
html: '<p>Hi!</p>',
})
);Retry Pattern with Exponential Backoff
import { HiveForgeError } from '@producthacker/hiveforge-sdk';
async function withRetry<T>(
operation: () => Promise<T>,
maxRetries = 3,
baseDelayMs = 1000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
// Don't retry client errors (4xx) except rate limits (429)
if (error instanceof HiveForgeError) {
if (error.status && error.status >= 400 && error.status < 500 && error.status !== 429) {
throw error;
}
}
if (attempt === maxRetries) {
throw error;
}
const delay = baseDelayMs * Math.pow(2, attempt);
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
// TypeScript requires this, but it's unreachable
throw new Error('Retry failed');
}
// Usage
const response = await withRetry(() =>
hiveforge.ai.complete({
messages: [{ role: 'user', content: 'Hello!' }],
})
);Using the Event System for Error Monitoring
// Set up global error monitoring
hiveforge.on('entitlements:error', (error) => {
// Log to your error tracking service
console.error('Entitlement refresh failed:', error.message);
// e.g., Sentry.captureException(error);
});
hiveforge.on('quota:exceeded', ({ resource, used, limit }) => {
console.error(`Quota exceeded for ${resource}: ${used}/${limit}`);
// Notify admin, send alert, etc.
});
hiveforge.on('quota:warning', ({ resource, used, limit }) => {
const percent = Math.round((used / limit) * 100);
console.warn(`${resource} quota at ${percent}%`);
});
hiveforge.on('status:changed', ({ previous, current }) => {
if (current === 'suspended') {
console.error('Deployment has been suspended!');
// Take action: notify user, disable features, etc.
}
});Comprehensive Error Handler
import {
HiveForgeError,
AIProxyException,
BillingProxyException,
EmailProxyException,
VectorProxyException,
WebhookProxyException,
} from '@producthacker/hiveforge-sdk';
function handleHiveForgeError(error: unknown): string {
if (error instanceof AIProxyException) {
if (error.isQuotaExceeded) {
return 'AI usage limit reached. Please upgrade your plan.';
}
return `AI service error: ${error.message}`;
}
if (error instanceof BillingProxyException) {
return `Billing error: ${error.message}`;
}
if (error instanceof EmailProxyException) {
if (error.creditsRequired) {
return `Not enough credits to send email. Need ${error.creditsRequired}, have ${error.creditsAvailable}.`;
}
return `Email error: ${error.message}`;
}
if (error instanceof VectorProxyException) {
if (error.creditsRequired) {
return `Not enough credits for vector operation. Need ${error.creditsRequired}, have ${error.creditsAvailable}.`;
}
return `Vector search error: ${error.message}`;
}
if (error instanceof WebhookProxyException) {
return `Webhook delivery error: ${error.message}`;
}
if (error instanceof HiveForgeError) {
return `HiveForge error (${error.status ?? 'unknown'}): ${error.message}`;
}
if (error instanceof Error) {
return error.message;
}
return 'An unexpected error occurred';
}