Skip to content

Troubleshooting Guide

This guide covers common issues and their solutions when working with Centrali.


Authentication Issues

"Invalid client credentials" Error

Symptom:

{
  "error": "Unauthorized",
  "message": "Invalid client credentials"
}

Common Causes:

  1. Incorrect credentials
  2. Typo in client_id or client_secret
  3. Extra spaces or newlines in environment variables
  4. Using credentials from wrong workspace

  5. Service account deleted or rotated

  6. Credentials were invalidated

Solutions:

# Check for whitespace
echo "[$CENTRALI_CLIENT_ID]"  # Should have no spaces around it
echo "[$CENTRALI_CLIENT_SECRET]"

# Verify credentials in dashboard
# Settings → Service Accounts → Check your service account exists

# Test credentials manually
curl -X POST "https://auth.centrali.io/oidc/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CENTRALI_CLIENT_ID" \
  -d "client_secret=$CENTRALI_CLIENT_SECRET" \
  -d "scope=openid"

If still failing: - Create a new service account - Ensure you're using credentials from the correct workspace - Check that service account wasn't revoked


"Token expired" Error

Symptom:

{
  "error": "Unauthorized",
  "message": "Token expired"
}

Cause: JWT tokens expire after 7 hours.

Solution:

With SDK (automatic):

// SDK handles this automatically - no action needed
const centrali = new CentraliSDK({ clientId, clientSecret, ... });

Manual implementation:

let tokenCache = null;
let tokenExpiry = null;

async function getToken() {
  if (tokenCache && Date.now() < tokenExpiry) {
    return tokenCache;
  }

  const response = await fetch('https://auth.centrali.io/oidc/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.CENTRALI_CLIENT_ID,
      client_secret: process.env.CENTRALI_CLIENT_SECRET,
      scope: 'openid'
    })
  });

  const data = await response.json();
  tokenCache = data.access_token;
  // Refresh 5 min before expiration
  tokenExpiry = Date.now() + ((data.expires_in - 300) * 1000);

  return tokenCache;
}


Missing Authorization Header

Symptom:

{
  "error": "Unauthorized",
  "message": "Missing authorization header"
}

Solution:

# ❌ Wrong
curl https://api.centrali.io/data/workspace/my-workspace/api/v1/structures

# ✅ Correct
curl https://api.centrali.io/data/workspace/my-workspace/api/v1/structures \
  -H "Authorization: Bearer YOUR_TOKEN"


Data & Record Issues

Validation Errors When Creating Records

Symptom:

{
  "error": "Validation Failed",
  "details": [
    { "field": "email", "message": "Invalid email format" }
  ]
}

Common Causes:

  1. Wrong data type

    // ❌ Wrong
    { price: "99.99" }  // String instead of number
    
    // ✅ Correct
    { price: 99.99 }    // Number
    

  2. Missing required fields

    // Check structure definition for required: true fields
    

  3. Invalid format

    // ❌ Wrong
    { email: "not-an-email" }
    
    // ✅ Correct
    { email: "user@example.com" }
    

  4. Violating constraints

    // ❌ Negative value when min: 0
    { price: -10 }
    
    // ✅ Correct
    { price: 10 }
    

Solution: - Check structure definition in dashboard - Validate data before sending to API - Read error details for specific field issues


"Structure not found" Error

Symptom:

{
  "error": "Not Found",
  "message": "Structure 'str_xyz' does not exist"
}

Causes: - Structure ID doesn't exist - Wrong workspace - Structure was deleted

Solutions:

# List all structures in workspace
curl https://api.centrali.io/data/workspace/YOUR_WORKSPACE/api/v1/structures \
  -H "Authorization: Bearer $TOKEN"

# Verify you're using correct workspace
echo $CENTRALI_WORKSPACE

# Check structure ID in dashboard
# Dashboard → Structures → Copy ID


"Record not found" Error

Symptom:

{
  "error": "Not Found",
  "message": "Record 'rec_xyz' does not exist"
}

Causes: - Record ID doesn't exist - Record was deleted - Wrong workspace - No permission to access

Solutions:

// Verify record exists
try {
  const record = await centrali.getRecord('Product', 'rec_xyz');
} catch (error) {
  if (error.response?.status === 404) {
    console.log('Record does not exist');
    // Handle gracefully
  }
}

// Query to find records instead
const records = await centrali.queryRecords('Product', {
  filter: 'slug = "my-product"'
});


Function Issues

Function Not Triggering

Symptom: Function code exists but doesn't execute when expected.

Checklist:

  1. Verify trigger is active

    # Dashboard → Functions → [Your Function] → Triggers
    # Ensure trigger status is "Active"
    

  2. Check trigger conditions

    // Trigger only fires if condition is true
    {
      "type": "record",
      "event": "afterCreate",
      "condition": "data.published = true"  // ← Must be true!
    }
    

  3. Check function status

    # Dashboard → Functions → [Your Function]
    # Status should be "Published" not "Draft"
    

  4. View function logs

    # Dashboard → Functions → [Your Function] → Logs
    # Check for errors or execution history
    


Function Timing Out

Symptom:

{
  "error": "Function Timeout",
  "message": "Function execution exceeded 30 seconds"
}

Cause: Function execution limit is 30 seconds.

Solutions:

  1. Optimize slow operations

    // ❌ Processing too many records
    exports.handler = async (event, context) => {
      const allRecords = await centrali.records.query({ limit: 10000 });
      for (const record of allRecords) {
        await processRecord(record); // Sequential!
      }
    };
    
    // ✅ Batch processing with limits
    exports.handler = async (event, context) => {
      const records = await centrali.records.query({ limit: 100 });
    
      // Process in parallel (faster)
      await Promise.all(records.map(processRecord));
    
      return { processed: records.length };
    };
    

  2. Break into smaller chunks

    // Chain multiple function executions
    exports.handler = async (event, context) => {
      const { offset = 0 } = event.data;
      const limit = 100;
    
      const records = await centrali.records.query({ limit, offset });
      await processRecords(records);
    
      // If more to process, trigger another run
      if (records.length === limit) {
        await centrali.functions.invoke('processBatch', {
          offset: offset + limit
        });
      }
    
      return { processed: records.length };
    };
    


Function Returns Error

Symptom: Function executes but returns error in logs.

Debugging:

  1. Check function logs

    # Dashboard → Functions → [Your Function] → Runs → [Run ID] → Logs
    

  2. Common issues:

  3. Missing environment variables
  4. External API errors
  5. Invalid data access

  6. Add logging

    exports.handler = async (event, context) => {
      console.log('Event:', JSON.stringify(event));
      console.log('Context workspace:', context.workspace);
    
      try {
        const result = await someOperation();
        console.log('Result:', result);
        return { success: true, data: result };
      } catch (error) {
        console.error('Error:', error.message);
        console.error('Stack:', error.stack);
        throw error;
      }
    };
    


Query Issues

Query Returns No Results

Symptom: Query executes but returns empty array when you expect results.

Debugging:

  1. Simplify the query

    // Start with simple query
    const all = await centrali.queryRecords('Product', {});
    console.log('Total records:', all.length);
    
    // Add filters one by one
    const filtered = await centrali.queryRecords('Product', {
      filter: 'inStock = true'
    });
    console.log('In stock:', filtered.length);
    

  2. Check filter syntax

    // ❌ Wrong
    filter: 'price > 100 AND inStock == true'  // Mixed operators
    
    // ✅ Correct
    filter: 'price > 100 AND inStock = true'   // Consistent operators
    

  3. Verify field names

    // Field names are case-sensitive
    filter: 'inStock = true'   // ✅ Correct
    filter: 'instock = true'   // ❌ Wrong case
    


"Query too complex" Error

Symptom:

{
  "error": "Bad Request",
  "message": "Query complexity limit exceeded"
}

Cause: Query has too many operations, filters, or nested includes.

Solution:

// ❌ Too complex
const query = `
  FROM Product
  WHERE condition1 AND condition2 AND condition3 ... (50+ conditions)
  INCLUDE category FROM Category
  INCLUDE tags FROM Tag
  INCLUDE reviews FROM Review
  INCLUDE manufacturer FROM Company
  INCLUDE ...  (many includes)
`;

// ✅ Simplify
const products = await centrali.queryRecords('Product', {
  filter: 'category = "electronics" AND inStock = true',
  limit: 100
});

// Fetch related data separately
for (const product of products) {
  product.reviews = await centrali.queryRecords('Review', {
    filter: `productId = "${product.id}"`
  });
}


Connection & Network Issues

Request Timeout

Symptom: Request hangs or times out.

Solutions:

  1. Check network connectivity

    # Ping Centrali
    curl -I https://centrali.io
    

  2. Increase timeout (SDK)

    const centrali = new CentraliSDK({
      // ... config
      axiosConfig: {
        timeout: 30000  // 30 seconds
      }
    });
    

  3. Check firewall/proxy

  4. Ensure outbound HTTPS (443) is allowed
  5. Check corporate proxy settings

Rate Limit Errors

Symptom:

{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded"
}

Solutions:

  1. Implement rate limit handling

    async function makeRequestWithRetry(fn) {
      try {
        return await fn();
      } catch (error) {
        if (error.response?.status === 429) {
          const retryAfter = parseInt(error.response.headers['retry-after']) || 60;
          console.log(`Rate limited. Waiting ${retryAfter}s...`);
          await new Promise(r => setTimeout(r, retryAfter * 1000));
          return await fn();
        }
        throw error;
      }
    }
    

  2. Optimize API usage

  3. Use bulk operations instead of loops
  4. Cache responses
  5. Use webhooks instead of polling

  6. Check rate limit headers

    console.log('Limit:', response.headers['x-ratelimit-limit']);
    console.log('Remaining:', response.headers['x-ratelimit-remaining']);
    

See Limits & Quotas for details.


Dashboard & Web Console Issues

Can't Access Dashboard

Solutions:

  1. Clear browser cache and cookies
  2. Try incognito/private mode
  3. Check for browser extension conflicts
  4. Try a different browser

Lost Service Account Secret

Symptom: Can't find client_secret after creation.

Solution: - Secrets are shown only once during creation - Cannot retrieve - must rotate to get new secret - Dashboard → Settings → Service Accounts → [Your Account] → Rotate Secret - Update your application with new secret immediately


Getting More Help

Before Contacting Support

Gather this information:

  1. Request ID (from error response)

    { "requestId": "req_abc123" }
    

  2. Workspace slug

  3. Timestamp of issue
  4. Steps to reproduce
  5. Error message and status code

Check Centrali Status

  • Visit status.centrali.io (if available)
  • Check for scheduled maintenance
  • Subscribe to status updates

Contact Support

  • Email: support@centrali.io
  • Dashboard: Settings → Support → New Ticket
  • Include request ID and details above


Quick Reference

Most Common Issues

Issue Quick Fix
"Invalid credentials" Check for typos, spaces in env vars
"Token expired" SDK handles automatically, or fetch new token
Validation error Check structure definition, verify data types
Function not triggering Verify trigger is active and conditions met
Function timeout Reduce processing, break into chunks
Rate limited Implement retry with backoff, optimize requests
Record not found Verify ID and workspace are correct

Useful Commands

# Test authentication
curl -X POST "https://auth.centrali.io/oidc/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CENTRALI_CLIENT_ID" \
  -d "client_secret=$CENTRALI_CLIENT_SECRET" \
  -d "scope=openid"

# List structures
curl "https://api.centrali.io/data/workspace/$WORKSPACE/api/v1/structures" \
  -H "Authorization: Bearer $TOKEN"

# Test connectivity
curl -I https://centrali.io