santifer/career-ops · error

glints: HTTP

Error message

glints: HTTP ${err.status} — ${detail}

What it means

graphqlPage issues the reverse-engineered GraphQL search request against Glints' v2-alc endpoint. When the HTTP layer raises an error carrying a status and body, the code tries JSON.parse(err.body) to extract errors[0].message as the detail; if that fails it falls back to the first 200 chars of the body, then throws 'glints: HTTP {status} — {detail}'. The message surfaces the upstream status plus whatever error detail the server returned.

Solutions

  1. Read the detail after 'HTTP <status> —' in the message: it contains the GraphQL error message or raw body prefix identifying the server-side complaint
  2. For 4xx schema drift, re-capture the current query from glints.com/id devtools and update graphqlQuery (custom query field on the entry) or the provider's DEFAULT_GRAPHQL_QUERY
  3. For 403/429, back off and retry later, reduce maxPages/pageSize, and confirm no proxy is interfering; consider being gentler with request frequency
  4. For 5xx, treat as transient — retry after a delay; check glints.com status if it persists
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight schema check before paginating:
const probe = await fetch('https://glints.com/api/v2-alc/graphql', { method: 'POST', headers: {'content-type':'application/json'}, body: JSON.stringify({ query: DEFAULT_GRAPHQL_QUERY, variables: { data: buildSearchCondition({}) } }) });
if (!probe.ok) console.warn(`glints GraphQL probe returned ${probe.status} — schema or access issue`);

Type guard

function isGlintsHttpError(e) { return e && typeof e.status === 'number' && typeof e.body === 'string'; }

Try / catch

try {
  const page = await graphqlPage(variables, offset);
} catch (e) {
  const m = /glints: HTTP (\d+)/.exec(e.message);
  if (m && (m[1] === '429' || m[1].startsWith('5'))) {
    await sleep(backoffMs);
    return graphqlPage(variables, offset); // retry transient failures
  }
  if (m && m[1].startsWith('4')) console.error(`Glints query rejected (${m[1]}) — likely schema drift; re-capture query from glints.com devtools`);
  throw e;
}

Prevention

When it happens

Trigger: The Glints GraphQL endpoint returns a non-2xx response: a 4xx for a malformed/changed query (the searchJobsV3 schema is reverse-engineered and may change), a 403/429 from bot protection or rate limiting, or a 5xx outage. graphqlPage then throws with the status and body-derived detail.

Common situations: Glints renames or restructures the searchJobsV3 operation (schema drift — the file explicitly warns the schema may change); rate limiting or Cloudflare blocking the browser-like user-agent; transient 5xx during an incident; pageSize/maxPages pushing the server to reject a request.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/080cbf5d00e33711. Report an issue: GitHub.

Appendix: source

Thrown at providers/glints.mjs:176

        'user-agent': BROWSER_LIKE_USER_AGENT,
        'origin': 'https://glints.com',
        'referer': 'https://glints.com/id/opportunities/jobs/explore',
      },
      body,
      redirect: 'error',
    });
    return res;
  } catch (err) {
    // On POST, some servers return non-JSON errors; attempt text fallback
    if (err.status && err.body) {
      let detail = '';
      try {
        const parsed = JSON.parse(err.body);
        detail = parsed.errors?.[0]?.message || err.body.slice(0, 200);
      } catch {
        detail = err.body.slice(0, 200);
      }
      throw new Error(`glints: HTTP ${err.status} — ${detail}`);
    }
    throw err;
  }
}

/** @type {Provider} */
export default {
  id: 'glints',

  detect(_entry) {
    // Glints is a job board aggregator, not a company ATS.
    // Auto-detection is intentionally not supported —
    // use `provider: glints` explicitly in portals.yml.
    return null;
  },

  async fetch(entry, ctx) {
    const apiUrl = entry.api || DEFAULT_API;

View on GitHub (pinned to aac998c7ed)