nanocoai/nanoclaw · error · Error

url must not contain credentials or fragments; use OneCLI fo

Error message

url must not contain credentials or fragments; use OneCLI for authentication

What it means

The MCP url contains embedded userinfo (username/password) or a #fragment, which parseMcpServerConfig rejects. NanoClaw routes all credentials through the OneCLI vault, never through the URL, so this shape is treated as a secret-leak risk.

Source

Thrown at src/container-config.ts:162

  }

  if (url !== undefined) {
    if (command !== undefined) throw new Error('Provide exactly one of command or url');
    if (input.args !== undefined || input.env !== undefined || input.cwd !== undefined) {
      throw new Error('args, env, and cwd are only valid with command');
    }
    let parsed: URL;
    try {
      parsed = new URL(url);
    } catch (err) {
      throw new Error('url must be a valid HTTP(S) URL', { cause: err });
    }
    const loopback = ['localhost', '127.0.0.1', '[::1]', 'host.docker.internal'].includes(parsed.hostname);
    if (parsed.protocol !== 'https:' && !(parsed.protocol === 'http:' && loopback)) {
      throw new Error('url must use HTTPS (plain HTTP is allowed only for localhost and host.docker.internal)');
    }
    if (parsed.username || parsed.password || parsed.hash) {
      throw new Error('url must not contain credentials or fragments; use OneCLI for authentication');
    }
    for (const key of parsed.searchParams.keys()) {
      if (SECRET_QUERY_KEY_RE.test(key.replace(CAMEL_SPLIT_RE, '$1_$2'))) {
        throw new Error(`url query parameter "${key}" looks like a credential; use OneCLI for authentication`);
      }
    }
    const headers = parseStringRecord(input.headers, 'headers');
    return {
      type: 'http',
      url,
      ...(headers === undefined ? {} : { headers }),
      ...(instructions === undefined ? {} : { instructions }),
    };
  }
  if (command === undefined) throw new Error('Provide exactly one of command or url');

  if (input.headers !== undefined) throw new Error('headers is only valid with url');
  const args = input.args ?? [];

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Remove credentials from the URL and inject auth via OneCLI (headers are injected at request time)
  2. If the server needs a header, use the headers field (but keep secrets out — prefer OneCLI)
  3. Delete any #fragment from the url

Example fix

// before
{"url":"https://alice:secret@mcp.example.com/mcp"}
// after
{"url":"https://mcp.example.com/mcp"}  // auth via OneCLI
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(entry.url); if (u.username || u.password || u.hash) throw new UserError('no credentials or fragments in url — use OneCLI');

Type guard

const urlHasNoCreds = (s: string) => { const u = new URL(s); return !u.username && !u.password && !u.hash; };

Try / catch

catch (err) { if (err.message.includes('credentials or fragments')) moveToVault(); else throw err; }

Prevention

When it happens

Trigger: urls like https://user:pass@mcp.example.com/mcp or https://mcp.example.com/mcp#section in an http MCP entry.

Common situations: Copy-pasting a vendor quickstart URL that embeds an API key; using a fragment as a session marker; basic-auth style internal endpoints.

Understand the failure class

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/9c2cf537e188e238. Report an issue: GitHub.