can1357/oh-my-pi · error · Error

SearXNG Basic auth requires both searxng.basicUsername and s

Error message

SearXNG Basic auth requires both searxng.basicUsername and searxng.basicPassword, or SEARXNG_BASIC_USERNAME and SEARXNG_BASIC_PASSWORD.

What it means

SearXNG Basic auth is configured only partially: exactly one of username/password was found (settings searxng.basicUsername/basicPassword or env SEARXNG_BASIC_USERNAME/SEARXNG_BASIC_PASSWORD). RFC 7617 Basic auth needs both, so findAuth throws a plain Error describing the required pair.

Source

Thrown at packages/coding-agent/src/web/search/providers/searxng.ts:153

}

/** Build the RFC 7617 Basic auth credential using UTF-8 bytes. */
function buildBasicAuthValue(username: string, password: string): string {
	return Buffer.from(`${username}:${password}`, "utf-8").toString("base64");
}

/** RFC 7617 forbids C0 and C1 control characters in Basic auth credentials. */
function hasControlCharacters(value: string): boolean {
	return /[\u0000-\u001F\u007F-\u009F]/u.test(value);
}

/** Find SearXNG authentication from settings or environment. Basic auth takes precedence over bearer tokens. */
function findAuth(): SearXNGAuth | null {
	const basicUsername = findBasicUsername();
	const basicPassword = findBasicPassword();
	if (basicUsername !== null || basicPassword !== null) {
		if (basicUsername === null || basicPassword === null) {
			throw new Error(
				"SearXNG Basic auth requires both searxng.basicUsername and searxng.basicPassword, or SEARXNG_BASIC_USERNAME and SEARXNG_BASIC_PASSWORD.",
			);
		}
		if (basicUsername.includes(":")) {
			throw new Error("SearXNG Basic auth username cannot contain ':' because RFC 7617 uses it as the separator.");
		}
		if (hasControlCharacters(basicUsername) || hasControlCharacters(basicPassword)) {
			throw new Error("SearXNG Basic auth credentials must not contain RFC 7617 control characters.");
		}
		return { type: "basic", value: buildBasicAuthValue(basicUsername, basicPassword) };
	}

	const token = findToken();
	return token ? { type: "bearer", value: token } : null;
}

/** Find configured engine names/shortcuts from settings. */
function findEngines(): string | null {

View on GitHub (pinned to 9690622007)

Solutions

  1. Set both searxng.basicUsername and searxng.basicPassword in settings
  2. Or set both SEARXNG_BASIC_USERNAME and SEARXNG_BASIC_PASSWORD env vars
  3. If Basic auth is unintended, remove the half-configured key entirely and configure a bearer token instead

Example fix

// before
SEARXNG_BASIC_USERNAME=alice
// after
SEARXNG_BASIC_USERNAME=alice
SEARXNG_BASIC_PASSWORD=s3cret
Defensive patterns

Strategy: validation

Validate before calling

const u = process.env.SEARXNG_BASIC_USERNAME;
const p = process.env.SEARXNG_BASIC_PASSWORD;
if ((u === undefined) !== (p === undefined)) {
  throw new Error('Set both SEARXNG_BASIC_USERNAME and SEARXNG_BASIC_PASSWORD (or neither)');
}

Try / catch

try {
  const auth = searxngAuth();
} catch (err) {
  if (err instanceof Error && err.message.includes("requires both")) {
    // fix settings/env pair, or clear the half-set key and use a bearer token
  }
  throw err;
}

Prevention

When it happens

Trigger: findAuth (called via auth) detects basicUsername !== null XOR basicPassword !== null when locating SearXNG credentials.

Common situations: Setting only one of the two settings keys, exporting only one of the two env vars, secrets manager injecting only one value, renaming one key and forgetting the other.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/a49cc32b7ad7bbca. Report an issue: GitHub.