Skip to content

Errors

The BitMarks API uses standard HTTP status codes and returns consistent error responses.

All errors return a JSON object with an error field:

{
"error": "Human-readable error message"
}

In development mode, additional debugging information may be included:

{
"error": "Something went wrong",
"details": "Additional context",
"stack": "Error: Something went wrong\n at ..."
}

CodeNameDescription
200OKRequest succeeded
201CreatedResource created successfully
302FoundRedirect (OAuth callbacks)
CodeNameDescription
400Bad RequestInvalid request body or parameters
401UnauthorizedAuthentication required or invalid
403ForbiddenAccess denied to resource
404Not FoundResource does not exist
409ConflictResource conflict (e.g., duplicate)
422Unprocessable EntityValid syntax but semantic errors
426Upgrade RequiredWebSocket upgrade expected
429Too Many RequestsRate limit exceeded
CodeNameDescription
500Internal Server ErrorUnexpected server error
501Not ImplementedFeature not yet available
503Service UnavailableTemporary service outage

401

No session cookie:

{
"error": "Authentication required"
}

Invalid or expired session:

{
"error": "Invalid or expired session"
}

No refresh token:

{
"error": "No refresh token"
}

Refresh failed:

{
"error": "Failed to refresh token"
}
400

Invalid request body:

{
"error": "Invalid request body"
}

Invalid sync changes:

{
"error": "Invalid changes format"
}
404

Bookmark not found:

{
"error": "Bookmark not found"
}

Export not found:

{
"error": "Export not found"
}

API endpoint not found:

{
"error": "Not Found",
"path": "/api/v1/unknown"
}
501

Feature not implemented:

{
"error": "Not implemented"
}
500

Generic server error:

{
"error": "Internal Server Error"
}

Login initiation failed:

{
"error": "Failed to initiate login"
}

Logout failed:

{
"error": "Failed to logout"
}

Sync status failed:

{
"error": "Failed to get sync status",
"details": "Database connection failed"
}

async function apiRequest<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(url, {
...options,
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
// Try to refresh token
const refreshed = await refreshToken();
if (refreshed) {
// Retry request
return apiRequest(url, options);
}
// Redirect to login
window.location.href = '/login';
throw new Error('Session expired');
case 429:
// Rate limited - wait and retry
const retryAfter = response.headers.get('Retry-After') || '60';
await delay(parseInt(retryAfter) * 1000);
return apiRequest(url, options);
case 404:
throw new NotFoundError(error.error);
case 400:
throw new ValidationError(error.error);
default:
throw new APIError(error.error, response.status);
}
}
return response.json();
}
class APIError extends Error {
constructor(
message: string,
public status: number
) {
super(message);
this.name = 'APIError';
}
}
class NotFoundError extends APIError {
constructor(message: string) {
super(message, 404);
this.name = 'NotFoundError';
}
}
class ValidationError extends APIError {
constructor(message: string) {
super(message, 400);
this.name = 'ValidationError';
}
}
class AuthenticationError extends APIError {
constructor(message: string) {
super(message, 401);
this.name = 'AuthenticationError';
}
}
import { Component, ErrorInfo, ReactNode } from 'react';
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error?: Error;
}
class APIErrorBoundary extends Component<Props, State> {
state: State = { hasError: false };
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error('API Error:', error, info);
}
render() {
if (this.state.hasError) {
return this.props.fallback || (
<div>
<h2>Something went wrong</h2>
<p>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false })}>
Try again
</button>
</div>
);
}
return this.props.children;
}
}

Terminal window
curl -i https://app.bitmarks.sh/api/v1/bookmarks \
-b "bitmarks_session=YOUR_TOKEN"
Terminal window
# Check if session is valid
curl https://app.bitmarks.sh/api/v1/auth/session \
-b "bitmarks_session=YOUR_TOKEN"
Terminal window
# Verify API is reachable
curl https://app.bitmarks.sh/api/v1/health

If you encounter unexpected errors, please report them with:

  1. Endpoint - The API path called
  2. Method - GET, POST, PUT, DELETE
  3. Request body - (without sensitive data)
  4. Response - The error response received
  5. Timestamp - When the error occurred