mastra-ai/mastra · error

GitHub pull requests require an owner/repository source.

Error message

GitHub pull requests require an owner/repository source.

What it means

#repositoryClient parses the sourceId into { owner, repo } via splitRepoFullName and throws when parsing fails, because GitHub pull-request operations require a well-formed owner/repository full name to build the Octokit request.

Source

Thrown at mastracode/factory/src/integrations/github/integration.ts:712

    const octokit = this.getInstallationOctokit(installationId);
    try {
      const { data } = await octokit.issues.createComment({
        owner: parts.owner,
        repo: parts.repo,
        issue_number: issueNumber,
        body: input.body,
      });
      return { id: String(data.id), url: data.html_url };
    } catch (err) {
      if (isNotFoundError(err)) return null;
      throw err;
    }
  }

  #repositoryClient(connection: IntegrationConnection, sourceId: string) {
    const installationId = getGithubInstallationId(connection);
    const parts = splitRepoFullName(sourceId);
    if (!parts) throw new Error('GitHub pull requests require an owner/repository source.');
    return { octokit: this.getInstallationOctokit(installationId), parts };
  }

  async #listPullRequests(input: InputOf<'listPullRequests'>) {
    const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);
    const page = parsePositiveCursor(input.cursor);
    const response = await octokit.pulls.list({
      ...parts,
      state: input.state ?? 'open',
      per_page: LIST_PAGE_SIZE,
      page,
    });
    const pullRequests = response.data
      .filter(pr => input.includeDrafts !== false || !pr.draft)
      .map(pr => parsePullRequest(pr));
    return {
      pullRequests,
      nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass sourceId as the GitHub full name 'owner/repo'
  2. Normalize stored source identifiers to owner/repo when creating connections
  3. Use splitRepoFullName (or an equivalent check) on input before calling the integration to give a better upstream error
  4. Update stale connections after repository transfers/renames

Example fix

// before
await gh.listPullRequests({ connection, sourceId: 'my-repo' });
// after
await gh.listPullRequests({ connection, sourceId: 'acme/my-repo' });
Defensive patterns

Strategy: validation

Validate before calling

const parts = sourceId.split('/');
if (parts.length !== 2 || !parts[0] || !parts[1]) {
  throw new Error(`sourceId must be 'owner/repo', got: ${sourceId}`);
}

Type guard

function isRepoFullName(s: string): s is `${string}/${string}` {
  const [owner, repo, ...rest] = s.split('/');
  return rest.length === 0 && Boolean(owner && repo);
}

Try / catch

try {
  await gh.listPullRequests({ connection, sourceId });
} catch (e) {
  if (e.message === 'GitHub pull requests require an owner/repository source.') {
    // fix the stored source identifier for this connection
  } else throw e;
}

Prevention

When it happens

Trigger: Calling listPullRequests (or any PR operation routed through #repositoryClient) with a sourceId that is not in 'owner/repo' format — e.g. a bare repo name, a URL, a numeric repo id, or an empty string.

Common situations: Passing a database record id instead of the GitHub full name; users typing 'my-repo' without the owner; storing a clone URL in sourceId; renaming a repository and keeping a stale slug.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/e7f1bc2d10b1e398. Report an issue: GitHub.