Skip to main content

Error response format

Errors follow RFC 7807:
{
  "type": "https://docs.nova.dweet.com/embed-api/errors#validation-error",
  "code": "VALIDATION_ERROR",
  "status": 400,
  "message": "Request validation failed",
  "retryable": false,
  "traceId": "5c2f4f5b2c0a4ce0b6a31a1a18f8e9a1",
  "details": [
    {
      "field": "resume.url",
      "code": "invalid",
      "message": "Resume URL must be a valid URL"
    }
  ]
}
FieldDescription
typeRFC 7807 URI identifying the error category
codeMachine-readable error code for programmatic matching
statusHTTP status code
messageHuman-readable error description
retryableWhether retrying may succeed
traceIdTrace ID for debugging (also in X-Trace-Id header)
detailsField-level validation errors (when present)

When to retry

  • retryable: true: retry with exponential backoff
  • 429 RATE_LIMITED: wait for Retry-After header value
  • Other 4xx: fix the request first

Common error codes

CodeStatusAction
UNAUTHORIZED401Check API key and Authorization header
VALIDATION_ERROR400Fix the fields listed in details
ANSWER_MISMATCH400Answers must match the question set
CRITERIA_NOT_FOUND404Generate criteria for the job first
SCORING_JOB_NOT_FOUND404Verify scoringJobId exists for this tenant
RESUME_FETCH_FAILED422Check resume URL is accessible and not expired
RESUME_TOO_LARGE422File must be under 50 MB
RESUME_ENCRYPTED422Remove password protection
RESUME_PARSE_FAILED422Confirm valid PDF, DOC, or DOCX
RATE_LIMITED429Wait for Retry-After and retry
For the complete list, see the error code reference.

Error handling with the SDK

The TypeScript SDK retries automatically on 429 and 5xx errors with exponential backoff and Retry-After support. You only need to handle non-retryable errors:
import { Nova, NovaApiError } from '@nova-sdk/api';

const nova = new Nova({
  apiKey: process.env.NOVA_API_KEY!,
  tenantId: 'acme-corp',
});

try {
  const { scoringJob } = await nova.jobs.applications.scoringJobs.submit({
    jobId: 'job-123',
    applicationId: 'app-456',
    body: {
      resume: { type: 'url', url: 'https://storage.example.com/resumes/abc123.pdf' },
      jobDescription: 'We are looking for...',
    },
  });
} catch (err) {
  if (err instanceof NovaApiError) {
    console.log(err.code);      // e.g. 'VALIDATION_ERROR'
    console.log(err.status);    // e.g. 400
    console.log(err.retryable); // false
    console.log(err.traceId);   // for debugging
    console.log(err.details);   // field-level validation errors
  }
}
Disable retries if you want full control:
const nova = new Nova({
  apiKey: process.env.NOVA_API_KEY!,
  tenantId: 'acme-corp',
  retry: { maxRetries: 0 },
});

Manual retry logic (cURL / raw HTTP)

If you aren’t using the SDK, implement retries yourself:
async function novaRequest(url, { method, headers, body }) {
  const maxAttempts = 3;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const response = await fetch(url, {
      method,
      headers,
      body: body ? JSON.stringify(body) : undefined,
    });

    if (response.ok) {
      return response.json();
    }

    const error = await response.json();

    if (response.status === 429) {
      const retryAfterSeconds = Number(response.headers.get("Retry-After") ?? "60");
      await new Promise((r) => setTimeout(r, retryAfterSeconds * 1000));
      continue;
    }

    if (error.retryable && attempt < maxAttempts) {
      const delayMs = 250 * Math.pow(2, attempt - 1);
      await new Promise((r) => setTimeout(r, delayMs));
      continue;
    }

    throw Object.assign(new Error(error.message), { error });
  }
}

Debugging

When contacting support, include the traceId, your timestamp and endpoint, and the HTTP status code.