ANTIGRAVITY LABJP
Articles/Integrations
Integrations/2026-03-29Intermediate

Fixing External Service Integration Errors

Practical guide to diagnosing and fixing errors when integrating AI tools with external services like GitHub, Slack, Firebase, and cloud storage. Covers authentication, CORS, rate limits, and data format issues.

integration7API6external servicetroubleshooting105error12

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 CodeCauseFix
400 Bad RequestMalformed requestCheck request body and parameters
401 UnauthorizedAuthentication failedVerify API key or token
403 ForbiddenInsufficient permissionsCheck scopes and permissions
404 Not FoundEndpoint doesn't existVerify API endpoint URL
429 Too Many RequestsRate limit exceededImplement retry logic or caching
500 Internal Server ErrorAPI server errorRetry and check service status
CORS ErrorCross-origin request blockedUse 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 correctly

Fix:

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 settings

For 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 403

Fix 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.com

Fix:

// 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: authenticationCORSrate limitsdata formatnetwork. 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".

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Integrations2026-04-19
Gemini API Python Error Code Guide — Fixing RESOURCE_EXHAUSTED, SAFETY, INVALID_ARGUMENT in Antigravity Development
A practical guide to fixing common Gemini API Python SDK errors — RESOURCE_EXHAUSTED, SAFETY, INVALID_ARGUMENT, and DEADLINE_EXCEEDED — with real code examples for developers building with Antigravity.
Integrations2026-04-08
How to Fix Zapier, Make & n8n AI Integration Errors: Complete Troubleshooting Guide
AI integrations breaking in Zapier, Make, or n8n? This guide covers the root causes of auth errors, timeouts, and rate limits — with step-by-step fixes for each scenario.
Integrations2026-03-30
Complete Troubleshooting Guide for Antigravity MCP Connection Errors
Master MCP connection troubleshooting with step-by-step diagnosis, authentication fixes, and debugging techniques for seamless integration.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →