decolua/9router · error

Linkup Search requires an API key

Error message

Linkup Search requires an API key

What it means

buildLinkupRequest builds the HTTP request for the Linkup search provider. It reads the credential from params.token and refuses to proceed when it is missing, empty, or undefined, because Linkup's API authenticates every search request with a bearer API key and an unauthenticated call would just fail upstream with a 401. Throwing here gives a fast, clear failure at request-build time instead of a network round-trip.

Source

Thrown at open-sse/handlers/search/callers.js:228

    const dateRestrictMap = { day: "d1", week: "w1", month: "m1", year: "y1" };
    const dateRestrict = dateRestrictMap[params.timeRange];
    if (dateRestrict) qp.set("dateRestrict", dateRestrict);
  }
  if (typeof params.offset === "number" && params.offset > 0) {
    qp.set("start", String(Math.min(params.offset + 1, 91)));
  }
  return {
    url: `${resolveBaseUrl(config, params)}?${qp}`,
    init: {
      method: "GET",
      headers: { Accept: "application/json" },
    },
  };
}

function buildLinkupRequest(config, params) {
  const apiKey = params.token;
  if (!apiKey) throw new Error("Linkup Search requires an API key");

  const { includes, excludes } = parseDomainFilter(params.domainFilter);
  const requestedDepth = getProviderSetting(params, "depth");
  const depth =
    requestedDepth && ["fast", "standard", "deep"].includes(requestedDepth)
      ? requestedDepth
      : "standard";

  const body = {
    q: params.query,
    depth,
    outputType: "searchResults",
    maxResults: params.maxResults,
  };
  if (includes.length) body.includeDomains = includes;
  if (excludes.length) body.excludeDomains = excludes;
  if (params.timeRange && params.timeRange !== "any") {
    const today = new Date();

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Get an API key from Linkup (app.linkup.so) and configure it for the Linkup provider in the dashboard/accounts store
  2. Verify the params object passed to the search handler actually includes token: '...' before dispatching
  3. Check that the key is stored under the correct provider id (linkup) and is not an empty/whitespace string
  4. If running programmatically, add a pre-check `if (!params.token) throw ...` or default the token from an env var

Example fix

// before
const res = await search({ provider: 'linkup', query: 'latest news' });
// after
const res = await search({ provider: 'linkup', query: 'latest news', token: process.env.LINKUP_API_KEY });
Defensive patterns

Strategy: validation

Validate before calling

if (!params?.token || typeof params.token !== 'string' || !params.token.trim()) {
  throw new Error('Linkup search requires a non-empty token');
}

Type guard

function hasLinkupToken(params) {
  return typeof params?.token === 'string' && params.token.trim().length > 0;
}

Try / catch

try {
  const res = await search({ provider: 'linkup', query, token });
} catch (err) {
  if (err.message.includes('requires an API key')) {
    // prompt for/configure the Linkup API key and retry once configured
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the Linkup search route with params.token undefined, null, or an empty string — e.g. the account/credential was never configured in the dashboard, the API key field is blank, or the caller passes a params object that omitted `token`.

Common situations: Fresh install where the Linkup provider was enabled but no API key was pasted in; env/account store missing the LINKUP key; a code path that builds SearchRequestParams programmatically and forgets `token`; key stored under the wrong provider id so lookup returns undefined.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/186303782753fcda. Report an issue: GitHub.