nexu-io/open-design · error

public_github_repository_metric input.url must be a valid UR

Error message

public_github_repository_metric input.url must be a valid URL

What it means

Thrown by selectGithubRepositoryApiUrl when the input.url string cannot be parsed by the WHATWG URL constructor (new URL). This is the first validation gate for the public_github_repository_metric refresh source: the value must be a syntactically valid absolute URL before any host/path checks run. It exists because live-artifact refresh inputs are model-authored JSON, so untrusted/malformed strings must be rejected before any network call.

Source

Thrown at apps/daemon/src/live-artifacts/refresh.ts:657

  return asBoundedRefreshOutput({
    toolName: 'git.summary',
    isRepository: true,
    branch: branch.trim(),
    status: compactExecOutput(status),
    recentCommits: compactExecOutput(recentCommits),
    diffStat: compactExecOutput(diffStat),
  });
}

function selectGithubRepositoryApiUrl(input: PublicGithubRepositoryMetricInput): URL {
  const rawUrl = optionalString(input.url, 'input.url');
  if (rawUrl === undefined) throw new Error('public_github_repository_metric requires input.url');

  let url: URL;
  try {
    url = new URL(rawUrl);
  } catch {
    throw new Error('public_github_repository_metric input.url must be a valid URL');
  }

  if (url.protocol !== 'https:' || url.hostname !== 'api.github.com') {
    throw new Error('public_github_repository_metric only supports https://api.github.com repository URLs');
  }
  if (!/^\/repos\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(url.pathname)) {
    throw new Error('public_github_repository_metric only supports /repos/{owner}/{repo} URLs');
  }
  url.search = '';
  url.hash = '';
  url.username = '';
  url.password = '';
  return url;
}

function selectGithubFields(input: PublicGithubRepositoryMetricInput): string[] {
  if (input.fields === undefined) return ['stargazers_count', 'full_name', 'html_url', 'updated_at'];
  if (!Array.isArray(input.fields)) throw new Error('input.fields must be an array of strings');

View on GitHub (pinned to 5be4028344)

Solutions

  1. Set input.url to a full absolute URL beginning with 'https://', e.g. 'https://api.github.com/repos/<owner>/<repo>'.
  2. If the value comes from a template substitution, verify the variable is bound and non-empty before refresh runs.
  3. Trim the string and reject empty before constructing the source so the error surfaces at authoring time, not refresh time.

Example fix

// before
input: { url: 'repos/octocat/Hello-World' }
// after
input: { url: 'https://api.github.com/repos/octocat/Hello-World' }
Defensive patterns

Strategy: validation

Validate before calling

function assertGithubApiUrl(raw: unknown): URL {
  if (typeof raw !== 'string' || raw.length === 0) throw new Error('input.url required');
  let u: URL;
  try { u = new URL(raw); } catch { throw new Error('input.url is not a valid URL'); }
  return u;
}
// call before building the refresh source

Type guard

function isUrlString(v: unknown): v is string {
  if (typeof v !== 'string' || v.length === 0) return false;
  try { new URL(v); return true; } catch { return false; }
}

Prevention

When it happens

Trigger: A live artifact refresh source of type daemon_tool with toolName 'public_github_repository_metric' whose input.url is undefined-ish handled elsewhere but defined as empty string '', a relative path like 'repos/foo/bar', a malformed string like 'ht!tp://api.github.com', or any value new URL() rejects.

Common situations: Model emits input.url without a scheme (e.g. 'api.github.com/repos/...'); agent writes a GitHub web URL intending it as API URL but typos the scheme; JSON template used a placeholder like '${URL}' that was never substituted; trailing whitespace or invisible characters from a copied cell.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/ccd02f7da223ce65. Report an issue: GitHub.