actualbudget/actual · warning

Invalid url parameter

Error message

Invalid url parameter

What it means

The proxy parses the supplied url query parameter with `new URL(...)`. If parsing throws (malformed URL), the proxy returns 400 'Invalid url parameter'. This catches syntactically invalid targets before any network work or allowlist checks happen.

Source

Thrown at packages/sync-server/src/app-cors-proxy.js:145

  }

  const targetUrlString = req.query.url;

  if (!targetUrlString) {
    return res.status(400).json({ error: 'Missing url parameter' });
  }

  // Validate session/token
  const session = await validateSession(req, res);
  if (!session) {
    return; // validateSession already sent the response
  }

  let url;
  try {
    url = new URL(targetUrlString);
  } catch {
    return res.status(400).json({ error: 'Invalid url parameter' });
  }

  // Fetch the latest allowlist
  try {
    await fetchAllowlist();
  } catch (error) {
    console.error('Failed to fetch allowlist:', error);
    return res.status(403).json({
      error: 'URL not allowed',
      message: 'Unable to verify allowlist',
    });
  }

  // Check if the URL is allowed
  if (!isUrlAllowed(url.href)) {
    console.warn('Blocked request to unauthorized URL:', url.href);
    return res.status(403).json({
      error: 'URL not allowed',

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Ensure the target is an absolute URL including the scheme (https://...) before encoding it into the query string.
  2. Run `new URL(target)` client-side to validate, and use encodeURIComponent when building the query.
  3. Log the raw url query value received by the server to spot encoding corruption.

Example fix

// before
const q = `/cors-proxy?url=${target}`; // unencoded
// after
const u = new URL(target); // throws early if invalid
const q = `/cors-proxy?url=${encodeURIComponent(u.href)}`;
Defensive patterns

Strategy: validation

Validate before calling

let parsed;
try { parsed = new URL(target); } catch {
  throw new Error(`Invalid proxy target: ${target}`);
}
if (!/^https?:$/.test(parsed.protocol)) throw new Error('Only http(s) targets are supported');
const proxied = `/cors-proxy?url=${encodeURIComponent(parsed.href)}`;

Type guard

function isAbsoluteHttpUrl(s) {
  try { const u = new URL(s); return u.protocol === 'http:' || u.protocol === 'https:'; }
  catch { return false; }
}

Try / catch

try {
  return await proxy(target);
} catch (e) {
  if (e.status === 400 && /Invalid url/.test(e.message)) {
    console.error(`Target '${target}' is not a valid absolute URL`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a string without a scheme (e.g. url=example.com/list.json), a url with illegal characters from incomplete encoding, or a truncated/garbled query value.

Common situations: Forgetting the https:// scheme; double-encoding or not encoding the target so special characters (&, ?, spaces) corrupt the value; concatenating base URLs and paths incorrectly.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/a7ff7896b7edd1e4. Report an issue: GitHub.