From clickup-pack
Diagnoses ClickUp API v2 errors by HTTP status and ECODE, fixing 400 bad requests, 401 OAuth issues, 429 rate limits, 403/404 problems with curl diagnostics.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin clickup-packThis skill is limited to using the following tools:
Reference for ClickUp API v2 errors. All errors return JSON with `err` (message) and optionally `ECODE` (error code).
Executes ClickUp API incident response: triage via bash/curl checks for status/auth/rate-limits/latency, decision tree, error fixes (401/429/500), mitigation.
Diagnoses and fixes common MindTickle API errors including 401 invalid key, 403 permissions, 404 not found, and 429 rate limits. Includes curl diagnostic script.
Debugs and resolves common MaintainX API errors like 400 Bad Request, 401 Unauthorized, and 403 Forbidden with curl diagnostics, bash tests, and concrete fixes.
Share bugs, ideas, or general feedback.
Reference for ClickUp API v2 errors. All errors return JSON with err (message) and optionally ECODE (error code).
{
"err": "Space not found",
"ECODE": "ITEM_015"
}
| Situation | Response | Fix |
|---|---|---|
| Missing required field | {"err": "Task name required"} | Include name in request body |
| Invalid field value | {"err": "Invalid priority"} | Priority must be 1-4 or null |
| Malformed JSON | {"err": "Unexpected token"} | Validate JSON before sending |
| Invalid custom field value | {"err": "Invalid value for field"} | Match value to field type |
| ECODE | Cause | Solution |
|---|---|---|
| OAUTH_017 | Token malformed or missing | Include Authorization: <token> header |
| OAUTH_023 | Workspace not authorized for token | User must re-authorize workspace in OAuth flow |
| OAUTH_026 | Token revoked by user | Generate new personal token or re-authenticate |
| OAUTH_027 | Workspace not authorized | Re-authorize via OAuth, ensuring workspace scope |
| OAUTH_029-045 | Various workspace auth failures | Re-run OAuth flow for the specific workspace |
# Diagnose: verify your token works
curl -s -w "\nHTTP %{http_code}\n" \
https://api.clickup.com/api/v2/user \
-H "Authorization: $CLICKUP_API_TOKEN"
| Situation | Fix |
|---|---|
| No access to space/folder/list | Verify user has access to that part of the hierarchy |
| Insufficient role permissions | Need admin role for destructive operations |
| Guest access limitation | Guests have restricted API access |
# Common causes: wrong ID, deleted resource, wrong hierarchy level
# Verify the resource exists:
curl -s https://api.clickup.com/api/v2/task/TASK_ID \
-H "Authorization: $CLICKUP_API_TOKEN" | jq '.id, .name'
Rate limits vary by plan (per token, per minute):
# Check rate limit headers on any response
curl -s -D - https://api.clickup.com/api/v2/user \
-H "Authorization: $CLICKUP_API_TOKEN" 2>&1 | grep -i ratelimit
# Headers returned:
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 95
# X-RateLimit-Reset: 1695000060 (Unix timestamp)
Check ClickUp Status Page first.
# Quick status check
curl -s https://status.clickup.com/api/v2/summary.json | \
jq '.status.description'
#!/bin/bash
echo "=== ClickUp API Diagnostics ==="
# 1. Auth check
echo -n "Auth: "
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
https://api.clickup.com/api/v2/user \
-H "Authorization: $CLICKUP_API_TOKEN")
[ "$HTTP_CODE" = "200" ] && echo "OK" || echo "FAILED ($HTTP_CODE)"
# 2. Rate limit check
echo -n "Rate limit remaining: "
curl -s -D - https://api.clickup.com/api/v2/user \
-H "Authorization: $CLICKUP_API_TOKEN" 2>&1 | \
grep "X-RateLimit-Remaining" | awk '{print $2}'
# 3. Workspace access
echo "Workspaces:"
curl -s https://api.clickup.com/api/v2/team \
-H "Authorization: $CLICKUP_API_TOKEN" | jq -r '.teams[] | " \(.id): \(.name)"'
async function handleClickUpError(response: Response): Promise<never> {
const body = await response.json().catch(() => ({ err: 'Unknown' }));
switch (response.status) {
case 401:
throw new Error(`Auth failed (${body.ECODE}): Re-check token or re-authorize`);
case 429: {
const resetAt = response.headers.get('X-RateLimit-Reset');
const waitMs = resetAt ? (parseInt(resetAt) * 1000 - Date.now()) : 60000;
throw new Error(`Rate limited. Retry after ${Math.ceil(waitMs / 1000)}s`);
}
case 404:
throw new Error(`Resource not found: ${body.err}`);
default:
throw new Error(`ClickUp API ${response.status}: ${body.err}`);
}
}
For comprehensive debugging, see clickup-debug-bundle.