Mintplex-Labs/anything-llm · error · Error

AGENT_KEENABLE_API_URL must use https:// (or target a…

Error message

AGENT_KEENABLE_API_URL must use https:// (or target a loopback host).

What it means

The Keenable web-search plugin validates the optional AGENT_KEENABLE_API_URL override before using it as the search endpoint. It parses the URL and rejects any value whose protocol is not https: unless the hostname is a loopback host (localhost, 127.0.0.1, ::1, host.docker.internal). This guard prevents API keys and search queries from being sent over plaintext http to non-local hosts, where they could be intercepted.

Solutions

  1. Change AGENT_KEENABLE_API_URL to use https:// (terminate TLS on the endpoint or front it with a reverse proxy like nginx/Caddy with a certificate).
  2. If the endpoint is genuinely local, use one of the whitelisted hostnames: http://localhost:PORT, http://127.0.0.1:PORT, http://[::1]:PORT, or http://host.docker.internal:PORT (when running in Docker).
  3. If the env var is not needed, unset AGENT_KEENABLE_API_URL entirely — the plugin then defaults to the built-in https://api.keenable.ai.
  4. For a plain-http endpoint on another address, extend the loopback whitelist in server/utils/agents/aibitat/plugins/web-browsing.js (lines 1358-1363) — only do this on trusted networks.

Example fix

// before
AGENT_KEENABLE_API_URL=http://api.keenable.ai
// after
AGENT_KEENABLE_API_URL=https://api.keenable.ai
Defensive patterns

Strategy: validation

Validate before calling

function isKeenableUrlSafe(raw) {
  try {
    const u = new URL(raw);
    const loopback = ["localhost", "127.0.0.1", "::1", "host.docker.internal"];
    return u.protocol === "https:" || loopback.includes(u.hostname);
  } catch {
    return false;
  }
}
// before starting the agent:
if (process.env.AGENT_KEENABLE_API_URL && !isKeenableUrlSafe(process.env.AGENT_KEENABLE_API_URL))
  throw new Error("AGENT_KEENABLE_API_URL must use https:// (or target a loopback host).");

Type guard

function isHttpsOrLoopback(url) {
  if (!(url instanceof URL)) return false;
  const loopback = ["localhost", "127.0.0.1", "::1", "host.docker.internal"];
  return url.protocol === "https:" || loopback.includes(url.hostname);
}

Try / catch

try {
  await agent._keenableSearch(query);
} catch (e) {
  if (e.message.includes("must use https://")) {
    console.error("Fix AGENT_KEENABLE_API_URL:", e.message);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: AGENT_KEENABLE_API_URL is set to an http:// URL (e.g. http://api.keenable.ai or http://my-proxy.example.com) whose hostname is not one of the four whitelisted loopback names; the error is thrown inside setup when the plugin parses the env var at line 1357-1369.

Common situations: Developers self-hosting a Keenable proxy behind plain http on a remote VM, typos like 'http://' copied from docs, pointing at an internal IP (e.g. http://10.0.0.5:8080) that is not in the loopback whitelist, or forgetting a reverse-proxy TLS termination step. Note even 0.0.0.0 or a LAN hostname fails because only the four literal names pass.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@a145d4d87d (2026-09-15). Data as JSON: /api/errors/279e35b8579ee878. Report an issue: GitHub.

Appendix: source

Thrown at server/utils/agents/aibitat/plugins/web-browsing.js:1367

            return result;
          },

          _keenableSearch: async function (query) {
            const apiKey = (process.env.AGENT_KEENABLE_API_KEY || "").trim();
            let baseUrl = "https://api.keenable.ai";
            if (process.env.AGENT_KEENABLE_API_URL) {
              try {
                const parsed = new URL(process.env.AGENT_KEENABLE_API_URL);
                const isLoopback = [
                  "localhost",
                  "127.0.0.1",
                  "::1",
                  "host.docker.internal",
                ].includes(parsed.hostname);
                if (parsed.protocol === "https:" || isLoopback)
                  baseUrl = parsed.origin;
                else
                  throw new Error(
                    "AGENT_KEENABLE_API_URL must use https:// (or target a loopback host)."
                  );
              } catch (e) {
                this.super.handlerProps.log(
                  `invalid Keenable Search URL: ${e.message}`
                );
                return `Keenable search is misconfigured: ${e.message}`;
              }
            }

            this.super.introspect(
              `${this.caller}: Using Keenable to search for "${
                query.length > 100 ? `${query.slice(0, 100)}...` : query
              }"`
            );

            const headers = {
              "Content-Type": "application/json",

View on GitHub (pinned to a145d4d87d)