When you integrate Antigravity with external services like GitHub, Slack, Firebase, or cloud storage, integration errors can derail your workflow. This guide covers the most common issues—authentication failures, CORS errors, rate limiting, and data format mismatches—with practical solutions for each.
Understanding Integration Flow and Common Error Patterns
When Antigravity communicates with external services, requests follow this pattern:
[Antigravity]
↓ HTTP/REST Request
[Firewall / Proxy]
↓ Request passes through
[External API Endpoint]
↓ Auth verification → Permission check → Request processing
[API Response]
↓ JSON / Data returned
[Antigravity] Client processing
Errors can occur at any step. Understanding the type of error message speeds up diagnosis.
Error Classification by HTTP Status Code
| Status Code | Cause | Fix |
|---|---|---|
| 400 Bad Request | Malformed request | Check request body and parameters |
| 401 Unauthorized | Authentication failed | Verify API key or token |
| 403 Forbidden | Insufficient permissions | Check scopes and permissions |
| 404 Not Found | Endpoint doesn't exist | Verify API endpoint URL |
| 429 Too Many Requests | Rate limit exceeded | Implement retry logic or caching |
| 500 Internal Server Error | API server error | Retry and check service status |
| CORS Error | Cross-origin request blocked | Use backend proxy or server-side calls |
Cause-Specific Solutions
Cause 1: Authentication Errors (401 / 403)
The most common issue is misconfigured API keys or tokens.
Diagnosis:
// Check actual request in console
console.log('Auth Header:', headers.Authorization);
// Output: Authorization: Bearer YOUR_API_KEY or undefined
// If undefined, authentication isn't set up correctlyFix:
For GitHub API:
// Correct approach: Use Personal Access Token (PAT)
const github = new Octokit({
auth: process.env.GITHUB_TOKEN, // Load from .env
});
// .env file
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Test authentication
const user = await github.rest.users.getAuthenticated();
console.log('Authenticated as:', user.data.login);For Slack API:
// Use Bot Token from Slack App
const slack = new WebClient(process.env.SLACK_BOT_TOKEN);
// Verify scopes (required permissions granted)
// Example: chat:write, files:write must be in Bot Token scopes
const auth = await slack.auth.test();
console.log('Bot scopes:', auth.response_metadata.messages[0]);
// If scopes are missing, add them in Slack App settingsFor Google / Gemini API:
// Verify API key isn't expired
// Google Cloud Console > APIs & Services > Credentials > API Key
// Create a new key if problems persist
const genai = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const model = genai.getGenerativeModel({ model: "gemini-2-flash" });
// Test call
const result = await model.generateContent("Test prompt");Check token expiration:
// For JWT tokens, verify expiration
const jwt = require('jsonwebtoken');
const decoded = jwt.decode(token);
console.log('Token expires at:', new Date(decoded.exp * 1000));
// If expired, use refresh token to get a new one
if (Date.now() > decoded.exp * 1000) {
const newToken = await refreshToken(refreshTokenValue);
// Retry with new token
}Cause 2: CORS Errors
Occurs when calling external APIs directly from the browser:
Error message example:
Access to XMLHttpRequest at 'https://api.github.com/user' from origin 'http://localhost:3000'
has been blocked by CORS policy:
Response to preflight request doesn't have required access-control-allow-origin header.
Diagnosis:
# Check browser console for CORS error
# Network tab: Look for OPTIONS request returning 403Fix 1: Use a backend proxy (recommended):
// Antigravity backend
app.post('/api/github-proxy', async (req, res) => {
try {
// Call GitHub API from server (no CORS restriction)
const response = await fetch('https://api.github.com/user', {
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json'
}
});
const data = await response.json();
res.json(data); // Return to client
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Client-side
const response = await fetch('/api/github-proxy', { method: 'POST' });
const user = await response.json();Fix 2: Set CORS headers yourself:
// Antigravity backend (Express.js example)
const cors = require('cors');
// Allow specific origins only
app.use(cors({
origin: ['http://localhost:3000', 'https://yourdomain.com'],
credentials: true
}));Fix 3: Check external service CORS configuration:
- GitHub API: CORS-enabled by default
- Firebase: CORS-safe when using Firebase SDK
- Stripe: CORS-enabled (verify whitelisted domains in dashboard)
Cause 3: Rate Limit Errors (429)
When you've exceeded API rate limits:
Diagnosis:
# Check rate limit headers in response:
# X-RateLimit-Limit: 60
# X-RateLimit-Remaining: 0
# X-RateLimit-Reset: 1640000000 (Unix timestamp)Fix 1: Implement exponential backoff retry logic:
async function callApiWithRateLimit(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
// Rate limited
const retryAfter = error.response.headers['retry-after'] || Math.pow(2, i);
console.log(`Rate limited. Retrying after ${retryAfter}s`);
await new Promise(resolve =>
setTimeout(resolve, retryAfter * 1000)
);
} else {
throw error;
}
}
}
}
// Usage
const result = await callApiWithRateLimit(
() => github.rest.repos.get({ owner: 'google', repo: 'antigravity' })
);Fix 2: Implement request caching:
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 3600 }); // 1-hour cache
async function getGitHubUserCached(username) {
const cacheKey = `github-user-${username}`;
// Return from cache if available
const cached = cache.get(cacheKey);
if (cached) return cached;
// Call API if not cached
const response = await github.rest.users.getByUsername({ username });
// Store in cache
cache.set(cacheKey, response.data);
return response.data;
}Fix 3: Use batch requests or GraphQL:
// REST API requires multiple calls → easy to hit rate limits
// ❌ Inefficient
for (let i = 0; i < 100; i++) {
const repo = await github.rest.repos.get({
owner: 'google',
repo: `antigravity-${i}`
});
}
// ✅ Efficient: Get multiple repos in one GraphQL request
const query = `
query {
repository1: repository(owner: "google", name: "antigravity-1") { name }
repository2: repository(owner: "google", name: "antigravity-2") { name }
...(up to ~10 repos per request)
}
`;Cause 4: Data Format Mismatch
When API responses don't match your expected structure:
Diagnosis:
// Log the actual API response
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log('Response type:', typeof data);
console.log('Response keys:', Object.keys(data));
console.log('Full response:', JSON.stringify(data, null, 2));Fix 1: Use schema validation library:
const zod = require('zod');
// Define expected data structure
const UserSchema = zod.object({
id: zod.number(),
name: zod.string(),
email: zod.string().email(),
created_at: zod.string().datetime(),
});
// Validate API response
const response = await fetch('https://api.example.com/user/123');
const data = await response.json();
try {
const validData = UserSchema.parse(data);
console.log('Valid:', validData);
} catch (error) {
console.error('Data format mismatch:', error.errors);
// Example: [{ code: 'invalid_type', path: ['email'], message: 'Expected string, got undefined' }]
}Fix 2: Transform and map data:
// API returns snake_case, but your app uses camelCase
function convertSnakeToCamel(obj) {
if (Array.isArray(obj)) {
return obj.map(convertSnakeToCamel);
}
if (obj !== null && typeof obj === 'object') {
const result = {};
for (const key in obj) {
const camelKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
result[camelKey] = convertSnakeToCamel(obj[key]);
}
return result;
}
return obj;
}
// Usage
const apiData = {
user_id: 123,
user_name: 'John Doe',
created_at: '2026-03-29'
};
const appData = convertSnakeToCamel(apiData);
// { userId: 123, userName: 'John Doe', createdAt: '2026-03-29' }Cause 5: Network Issues and Timeouts
When API calls fail without response:
Diagnosis:
# Test network connectivity
ping api.github.com
curl -I https://api.github.com
# Test DNS resolution
nslookup api.github.comFix:
// Set timeout for requests
async function fetchWithTimeout(url, options = {}) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 seconds
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
return response;
} finally {
clearTimeout(timeoutId);
}
}
// Implement robust retry logic
async function robustFetch(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetchWithTimeout(url);
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000; // Exponential backoff
console.log(`Attempt ${i + 1} failed. Retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}Looking back
Troubleshooting external service integration works best by following this order: authentication → CORS → rate limits → data format → network. The code examples in each section provide practical patterns you can adapt for your needs. For deeper integration patterns, check "Building MCP Servers" and "GitHub Integration".