Claude-code-plugins hubspot-common-errors
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/hubspot-pack/skills/hubspot-common-errors" ~/.claude/skills/jeremylongshore-claude-code-plugins-hubspot-common-errors && rm -rf "$T"
manifest:
plugins/saas-packs/hubspot-pack/skills/hubspot-common-errors/SKILL.mdsource content
HubSpot Common Errors
Overview
Quick reference for the most common HubSpot API errors, their real error response bodies, and solutions.
Prerequisites
installed@hubspot/api-client- API credentials configured
- Access to application logs
Instructions
Step 1: Identify the Error
Check the HTTP status code and response body. HubSpot returns structured errors:
{ "status": "error", "message": "One or more validation errors occurred", "correlationId": "abc123-def456", "category": "VALIDATION_ERROR", "errors": [ { "message": "Property values were not valid: [{\"isValid\":false,\"message\":\"...\"}]", "context": { "propertyName": "email" } } ] }
Step 2: Match and Fix
401 Unauthorized
Real response:
{ "status": "error", "message": "Authentication credentials not found. This API supports OAuth 2.0 authentication and you can find more details at https://developers.hubspot.com/docs/methods/auth/oauth-overview", "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "category": "INVALID_AUTHENTICATION" }
Causes:
- Missing
headerAuthorization: Bearer - Expired OAuth access token (30-minute TTL)
- Revoked or regenerated private app token
Fix:
# Verify token is set and valid curl -s https://api.hubapi.com/crm/v3/objects/contacts?limit=1 \ -H "Authorization: Bearer $HUBSPOT_ACCESS_TOKEN" | jq .status # Should return null (success) or "error"
403 Forbidden
Real response:
{ "status": "error", "message": "This access token does not have proper permissions. (requires any of [crm.objects.contacts.write])", "correlationId": "...", "category": "MISSING_SCOPES" }
Fix: Add the missing scope to your private app in Settings > Integrations > Private Apps, then regenerate the token.
409 Conflict
Real response:
{ "status": "error", "message": "Contact already exists. Existing ID: 12345", "correlationId": "...", "category": "CONFLICT" }
Fix: Search before creating, or use batch upsert:
// Use search-first pattern const existing = await client.crm.contacts.searchApi.doSearch({ filterGroups: [{ filters: [{ propertyName: 'email', operator: 'EQ', value: email }], }], properties: ['email'], limit: 1, after: 0, sorts: [], }); if (existing.results.length > 0) { await client.crm.contacts.basicApi.update(existing.results[0].id, { properties }); } else { await client.crm.contacts.basicApi.create({ properties, associations: [] }); }
429 Too Many Requests
Real response:
{ "status": "error", "message": "You have reached your secondly limit.", "correlationId": "...", "category": "RATE_LIMITS" }
Headers returned:
X-HubSpot-RateLimit-Daily: 500000 X-HubSpot-RateLimit-Daily-Remaining: 499950 X-HubSpot-RateLimit-Secondly: 10 X-HubSpot-RateLimit-Secondly-Remaining: 0 Retry-After: 1
Fix: Honor
Retry-After header and use SDK built-in retries:
const client = new hubspot.Client({ accessToken: process.env.HUBSPOT_ACCESS_TOKEN!, numberOfApiCallRetries: 3, // auto-retries 429s with backoff });
400 Validation Error (Property)
Real response:
{ "status": "error", "message": "Property values were not valid: [{\"isValid\":false,\"message\":\"Property \\\"nonexistent_field\\\" does not exist\",\"error\":\"PROPERTY_DOESNT_EXIST\",\"name\":\"nonexistent_field\"}]", "correlationId": "...", "category": "VALIDATION_ERROR" }
Fix:
// List available properties for an object type // GET /crm/v3/properties/{objectType} const properties = await client.crm.properties.coreApi.getAll('contacts'); const propNames = properties.results.map(p => p.name); console.log('Available contact properties:', propNames);
400 Invalid Association
Real response:
{ "status": "error", "message": "association type id 999 doesn't exist between contact and company", "correlationId": "...", "category": "VALIDATION_ERROR" }
Common association type IDs:
| From | To | TypeId | Label |
|---|---|---|---|
| Contact | Company | 1 | Primary |
| Contact | Deal | 3 | -- |
| Company | Deal | 5 | -- |
| Contact | Ticket | 16 | -- |
| Note | Contact | 202 | -- |
| Task | Contact | 204 | -- |
| Note | Deal | 214 | -- |
404 Not Found (Archived Record)
Real response:
{ "status": "error", "message": "Object not found. objectType=contacts, objectId=12345. It may have been deleted.", "correlationId": "...", "category": "OBJECT_NOT_FOUND" }
Fix: The record may be archived. Check with
archived=true:
const contact = await client.crm.contacts.basicApi.getById( '12345', ['email'], undefined, undefined, true // archived = true );
Output
- Error identified by HTTP status and category
- Root cause determined
- Fix applied with working code
- Verified resolution
Error Handling
Catch-All Error Handler
import { HttpError } from '@hubspot/api-client/lib/codegen/crm/contacts'; async function handleHubSpotError(error: any): Promise<void> { const status = error?.code || error?.statusCode || 500; const body = typeof error?.body === 'string' ? JSON.parse(error.body) : error?.body || {}; console.error(`HubSpot API Error [${status}]`, { message: body.message, category: body.category, correlationId: body.correlationId, errors: body.errors, }); // Save correlationId for support tickets if (status >= 500) { console.error('HubSpot server error. Check https://status.hubspot.com'); } }
Examples
Quick Diagnostic Commands
# Check HubSpot API status curl -s https://status.hubspot.com/api/v2/summary.json | jq '.status.description' # Verify token and scopes curl -s https://api.hubapi.com/crm/v3/objects/contacts?limit=1 \ -H "Authorization: Bearer $HUBSPOT_ACCESS_TOKEN" \ -w "\nHTTP Status: %{http_code}\n" # Check rate limit headers curl -sI https://api.hubapi.com/crm/v3/objects/contacts?limit=1 \ -H "Authorization: Bearer $HUBSPOT_ACCESS_TOKEN" \ | grep -i ratelimit
Resources
Next Steps
For comprehensive debugging, see
hubspot-debug-bundle.