Skip to content

Error Handling & Troubleshooting

This guide helps you diagnose and resolve common issues when working with the Grizzly platform.

Common Error Patterns

Authentication Errors

Problem: Requests fail with authentication errors (401 Unauthorized).

Symptoms: - Authentication failed or Invalid API key - HTTP 401 status codes - SDK throws authentication-related errors

Solutions:

Verify API Key Ensure your API key is valid and has not been disabled:
# Test with curl
curl -H "Authorization: Bearer YOUR_API_KEY" \
     https://your-tenant.grizzlycbg.io/auth/apikey

# Expected: 200 OK with API key details
# If 401: API key is invalid or disabled
**Common causes:** - API key was disabled in the dashboard - Incorrect API key (check for typos, extra spaces) - API key belongs to a different tenant - API key has expired (if expiration is enabled)
Check API Key Format API keys must be passed as Bearer tokens in the Authorization header:
// Correct
headers: {
   'Authorization': 'Bearer apikey-123456-1234567890'
}

// Incorrect (missing "Bearer")
headers: {
   'Authorization': 'apikey-123456-1234567890'
}

Permission Errors

Problem: Requests fail with permission denied (403 Forbidden).

Symptoms: - Insufficient permissions or Access denied - HTTP 403 status codes - Operations fail even with valid authentication

Solutions:

Verify API Key Flags Check that your API key has the required permissions (flags):
# Get API key details
curl -H "Authorization: Bearer YOUR_API_KEY" \
     https://your-tenant.grizzlycbg.io/auth/apikey
**Common permission requirements:** | Operation | Required Flag | |-----------|---------------| | Create KeyRing | `keyring.create` | | Encrypt data | `keyring.[ring-name].encrypt` or `keyring.*.encrypt` | | Decrypt data | `keyring.[ring-name].decrypt` or `keyring.*.decrypt` | | Rotate keys | `keyring.[ring-name].rotate` or `keyring.*.rotate` | | Read activity | `activity.read` | | Create accounts | `account.create` | | Create API keys | `apikey.write` |
Check KeyRing-Specific Permissions If you can access some KeyRings but not others, verify KeyRing-specific flags:
// API key with limited access
flags: {
   "keyring.Finance.encrypt": true,      // Can encrypt with Finance
   "keyring.Finance.decrypt": true,      // Can decrypt with Finance
   "keyring.HR.encrypt": false           // Cannot use HR KeyRing
}
**Solution:** Request an API key update to grant access to the required KeyRings.

KeyRing Not Found

Problem: Operations fail because the KeyRing doesn't exist.

Symptoms: - KeyRing not found errors - HTTP 404 status codes when accessing KeyRings - SDK returns undefined when getting a KeyRing

Solutions:

Verify KeyRing Exists **Using SDK:**
const ring = await client.ring.get('Finance')

if (!ring) {
   console.log('KeyRing does not exist')
   // Create it
   const newRing = await client.ring.create('Finance')
}
**Using API:**
# List all KeyRings
curl -H "Authorization: Bearer YOUR_API_KEY" \
     https://your-tenant.grizzlycbg.io/ks/rings
Check KeyRing Name Case Sensitivity KeyRing names are case-insensitive but stored in lowercase:
// These all refer to the same KeyRing
await client.ring.get('Finance')   // Stored as 'finance'
await client.ring.get('finance')
await client.ring.get('FINANCE')

// Display name preserves casing
const ring = await client.ring.create('Finance')
console.log(ring.name)         // 'finance'
console.log(ring.displayName)  // 'Finance'

Decryption Failures

Problem: Data fails to decrypt even though it was encrypted successfully.

Symptoms: - Decryption failed or Invalid encrypted data - Authentication tag verification failed - Garbled or corrupted output

Solutions:

Verify Data Integrity Ensure encrypted data hasn't been modified:
// Encrypted data must be preserved exactly as returned
const encrypted = await ring.encrypt('data')

// ❌ Don't modify encrypted data
const modified = encrypted.substring(0, encrypted.length - 10)

// ✅ Store and retrieve encrypted data without changes
await ring.decrypt(encrypted)  // Works
await ring.decrypt(modified)   // Fails
**Common causes:** - Data truncated during storage or transmission - Encoding issues (base64 corruption, charset problems) - Data passed through systems that modify whitespace - Binary data treated as text
Check Private Key Availability For customer-managed keys, ensure the private key is accessible:
// Decryption with customer-managed keys
const privateKey = fs.readFileSync('./private.pem', 'utf-8')
const decrypted = await client.decrypt(encrypted, privateKey)

// Common issues:
// - Private key file path incorrect
// - Private key format wrong (must be PEM-encoded PKCS8)
// - Private key doesn't match the public key used for KeyRing
Validate Header Format The encrypted data must include a valid Grizzly header:
// Encrypted data structure:
// [Header][Encrypted Payload][Auth Tag]

// If you're manually handling encrypted data:
// - Don't strip the header
// - Don't separate header from payload
// - Keep all three components together

Network and Connection Errors

Problem: Requests timeout or fail to connect to the Grizzly platform.

Symptoms: - Connection refused or ECONNREFUSED - Timeout or Network error - SDK operations hang indefinitely

Solutions:

Verify Host URL Ensure the host URL is correct and accessible:
// ✅ Correct format
const client = await KeyClient.create({
   host: 'https://your-tenant.grizzlycbg.io',
   apikey: 'apikey-123456-1234567890'
})

// ❌ Common mistakes
host: 'http://your-tenant.grizzlycbg.io'   // Wrong protocol
host: 'your-tenant.grizzlycbg.io'          // Missing https://
host: 'https://your-tenant.grizzlycbg.io/' // Trailing slash
Test connectivity:
curl https://your-tenant.grizzlycbg.io/healthz
Check Firewall and Network Settings - Ensure outbound HTTPS (port 443) is allowed - Verify no proxy is blocking connections - Check if VPN or corporate firewall restricts access - Confirm DNS resolves the hostname correctly
Handle Timeouts Gracefully
async function encryptWithRetry(data, keyring, maxRetries = 3) {
   for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
         const ring = await client.ring.get(keyring)
         return await ring.encrypt(data)
      } catch (error) {
         if (error.message.includes('timeout') && attempt < maxRetries) {
            console.log(`Attempt ${attempt} failed, retrying...`)
            await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
            continue
         }
         throw error
      }
   }
}

Key Rotation Issues

Problem: Key rotation fails or behaves unexpectedly.

Symptoms: - Key rotation failed - New encryptions still use old key - Configuration changes don't trigger rotation

Solutions:

Verify Rotation Configuration Check KeyRing configuration for rotation settings:
const ring = await client.ring.get('Finance')
const config = await ring.getConfig()

console.log('Max encrypt count:', config.algos.aes256.maxEncryptCount)

// Rotation happens automatically when this count is reached
// Or manually with:
await ring.rotate()
Understand Rotation Behavior **Important points:** - Rotated keys are **never deleted** - Old encrypted data **still decrypts** after rotation - Only **new encryptions** use the new key - Rotation is **irreversible**
// Before rotation
const ring1 = await client.ring.get('Finance')
console.log('Active key:', ring1.activeKey.id)  // key-001

const data1 = await ring1.encrypt('Old data')

// Rotate
await ring1.rotate()

// After rotation
const ring2 = await client.ring.get('Finance')
console.log('Active key:', ring2.activeKey.id)  // key-002

const data2 = await ring2.encrypt('New data')

// Both decrypt successfully
await ring2.decrypt(data1)  // Works (uses key-001)
await ring2.decrypt(data2)  // Works (uses key-002)

SDK-Specific Errors

Module Not Found

Problem: Import errors when using the SDK.

Symptoms:

Error: Cannot find module '@grizzlycbg/grizzly-sdk'

Solutions:

Verify Installation
# Check if SDK is installed
npm list @grizzlycbg/grizzly-sdk

# If not installed
npm install @grizzlycbg/grizzly-sdk

# Verify package.json
cat package.json | grep grizzly-sdk
Check Node.js Version The SDK requires Node.js 20 or higher:
node --version  # Should be v20.x.x or higher

# If using older version, update Node.js
# https://nodejs.org/

Stream Handling Errors

Problem: Errors when encrypting/decrypting streams.

Symptoms: - Stream is not readable - Premature close - Incomplete file encryption/decryption

Solutions:

Handle Stream Events Properly
async function encryptFileStream(inputPath, outputPath, ring) {
   const readStream = fs.createReadStream(inputPath)
   const writeStream = fs.createWriteStream(outputPath)

   try {
      const encryptedStream = await ring.encrypt(readStream)

      return new Promise((resolve, reject) => {
         // Handle all stream events
         encryptedStream.pipe(writeStream)

         writeStream.on('finish', () => resolve())
         writeStream.on('error', reject)
         encryptedStream.on('error', reject)
         readStream.on('error', reject)
      })
   } catch (error) {
      // Cleanup on error
      readStream.destroy()
      writeStream.destroy()
      throw error
   }
}

API-Specific Errors

Invalid Request Body

Problem: API returns 400 Bad Request.

Symptoms:

{
  "error": "Invalid request body",
  "details": "Missing required field: name"
}

Solutions:

Validate Request Format **Common issues:** - Missing required fields - Incorrect data types - Invalid JSON syntax
// ❌ Incorrect
{
   ringname: 'Finance',  // Wrong field name
   displayName: 123      // Wrong type (should be string)
}

// ✅ Correct
{
   "name": "Finance",
   "displayName": "Finance Team"
}
Check Content-Type Header Ensure you're sending the correct content type:
# ✅ Correct
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer apikey-xxx" \
  -d '{"name":"Finance"}' \
  https://your-tenant.grizzlycbg.io/asym/keyrings

# ❌ Missing Content-Type
curl -X POST \
  -H "Authorization: Bearer apikey-xxx" \
  -d '{"name":"Finance"}' \
  https://your-tenant.grizzlycbg.io/asym/keyrings

Rate Limiting

Problem: Too many requests in a short time.

Symptoms: - HTTP 429 (Too Many Requests) - Rate limit exceeded errors

Solutions:

Implement Backoff Strategy
async function requestWithBackoff(fn, maxRetries = 3) {
   for (let i = 0; i < maxRetries; i++) {
      try {
         return await fn()
      } catch (error) {
         if (error.status === 429 && i < maxRetries - 1) {
            const delay = Math.pow(2, i) * 1000  // Exponential backoff
            console.log(`Rate limited, waiting ${delay}ms...`)
            await new Promise(resolve => setTimeout(resolve, delay))
            continue
         }
         throw error
      }
   }
}

// Usage
const result = await requestWithBackoff(async () => {
   return await fetch('https://your-tenant.grizzlycbg.io/ks/rings', {
      headers: { 'Authorization': 'Bearer apikey-xxx' }
   })
})
Batch Operations Instead of making many individual requests, batch where possible:
// ❌ Many sequential requests
for (const user of users) {
   await ring.encrypt(user.data)
}

// ✅ Parallel with concurrency limit
const limit = 10  // Max concurrent requests
for (let i = 0; i < users.length; i += limit) {
   const batch = users.slice(i, i + limit)
   await Promise.all(batch.map(user => ring.encrypt(user.data)))
}

Debugging Tips

Enable Debug Logging

SDK Debug Mode
// Set environment variable
process.env.GRIZZLY_DEBUG = 'true'

// Or enable in code
const client = await KeyClient.create({
   host: 'https://your-tenant.grizzlycbg.io',
   apikey: 'apikey-123456-1234567890',
   debug: true  // If supported
})

Test Connectivity

Health Check Test basic connectivity to the Grizzly platform:
# Health endpoint
curl https://your-tenant.grizzlycbg.io/healthz

# Expected response: {"status":"ok"}

Inspect Encrypted Data

Examine Header Encrypted data contains a header with metadata:
// Encrypted data structure (base64 encoded):
// [Version][Header Length][Header][Encrypted Payload][Auth Tag]

// To inspect (not for production):
const encrypted = await ring.encrypt('data')
const buffer = Buffer.from(encrypted, 'base64')

console.log('Total length:', buffer.length)
console.log('First 20 bytes:', buffer.slice(0, 20).toString('hex'))

Getting Help

If you're still experiencing issues:

  1. Check the Activity Feed - Review recent encryption/decryption operations for clues
  2. Verify API Key Status - Ensure API key is active and has required permissions
  3. Review Recent Changes - Check if KeyRing configuration or API key flags changed
  4. Test with Minimal Example - Isolate the issue with a simple test case
  5. Contact Support - Provide error messages, request IDs, and reproduction steps

Common Error Reference

Error Message Cause Solution
Authentication failed Invalid or disabled API key Verify API key is correct and active
Insufficient permissions Missing required flag Update API key flags
KeyRing not found KeyRing doesn't exist Create KeyRing or check name spelling
Decryption failed Corrupted data or wrong key Verify data integrity and private key
Invalid encrypted data Malformed header or payload Ensure data not modified after encryption
Connection refused Wrong host or network issue Check host URL and network connectivity
Timeout Network latency or server issue Implement retry logic with backoff
Rate limit exceeded Too many requests Reduce request rate or implement backoff
Invalid request body Missing/incorrect fields Validate request structure
Key rotation failed Permission or configuration issue Check rotation permissions and config