different-ai/openwork · error · PluginArchRouteFailure
invalid_github_materialization_context
invalid_github_materialization_context
Error message
GitHub connector target is missing required materialization context.
What it means
Thrown (409) when a GitHub connector target lacks any of the three required materialization inputs: an installationId (from the connector instance's instanceConfigJson), a branch (from targetConfig.branch or the target's externalTargetRef), or a repositoryFullName (from targetConfig.repositoryFullName or the target's remoteId). Materialization cannot proceed against GitHub without all three.
Source
Thrown at ee/apps/den-api/src/routes/org/plugin-system/store.ts:6615
async function materializeGithubImportPlans(input: {
connectorInstance: ReturnType<typeof serializeConnectorInstance>
connectorSyncEventId?: ConnectorSyncEventId
connectorTarget: ReturnType<typeof serializeConnectorTarget>
context: PluginArchActorContext
importPlans: Array<{ fileShaByPath?: Record<string, string>; mapping: ReturnType<typeof serializeConnectorMapping>; paths: string[] }>
sourceRevisionRef: string
}) {
const config = githubConnectorAppConfig()
const targetConfig = input.connectorTarget.targetConfigJson && typeof input.connectorTarget.targetConfigJson === "object"
? input.connectorTarget.targetConfigJson as Record<string, unknown>
: {}
const branch = typeof targetConfig.branch === "string" ? targetConfig.branch : input.connectorTarget.externalTargetRef ?? ""
const installationId = typeof input.connectorInstance.instanceConfigJson === "object" && input.connectorInstance.instanceConfigJson && typeof (input.connectorInstance.instanceConfigJson as Record<string, unknown>).installationId === "number"
? (input.connectorInstance.instanceConfigJson as Record<string, unknown>).installationId as number
: null
const repositoryFullName = typeof targetConfig.repositoryFullName === "string" ? targetConfig.repositoryFullName : input.connectorTarget.remoteId
if (!installationId || !branch || !repositoryFullName) {
throw new PluginArchRouteFailure(409, "invalid_github_materialization_context", "GitHub connector target is missing required materialization context.")
}
const token = await getGithubInstallationAccessToken({
config,
installationId,
})
const organizationId = input.context.organizationContext.organization.id
const plannedFiles = input.importPlans.flatMap((plan) => plan.paths.map((path) => ({
mapping: plan.mapping,
path,
sourceFileRevisionRef: plan.fileShaByPath?.[path] ?? null,
})))
const existingBindings = await Promise.all(plannedFiles.map((file) => findActiveConnectorSourceBinding({
connectorMappingId: file.mapping.id,
externalLocator: file.path,
organizationId,
})))
const fetchResults = await fetchGithubImportFilesWithRevisionGuard({View on GitHub (pinned to 2b7df46e8a)
Solutions
- Complete the GitHub App installation so instanceConfigJson contains a numeric installationId.
- Set `branch` (or externalTargetRef) and `repositoryFullName` (or remoteId) on the connector target config, e.g. via updateConnectorTarget.
- Re-create the connector target through the normal install flow instead of hand-editing config so all fields are populated consistently.
Example fix
// before
await materializePlugin({ connectorTargetId }) // targetConfig = { repositoryFullName: 'org/repo' } -> no branch, no installationId
// after
await updateConnectorTarget(connectorTargetId, { config: { repositoryFullName: 'org/repo', branch: 'main' } })
await completeGithubConnectorInstall({ installationId: 12345, state }) // populates instanceConfigJson.installationId
await materializePlugin({ connectorTargetId }) Defensive patterns
Strategy: validation
Validate before calling
const installationId = instance.instanceConfigJson && typeof instance.instanceConfigJson === 'object' ? (instance.instanceConfigJson as Record<string, unknown>).installationId : null
const branch = targetConfig.branch ?? target.externalTargetRef
const repositoryFullName = targetConfig.repositoryFullName ?? target.remoteId
if (!installationId || !branch || !repositoryFullName) throw new Error('GitHub materialization requires installationId, branch, and repositoryFullName') Type guard
function hasGithubMaterializationContext(t: { installationId: unknown; branch: unknown; repositoryFullName: unknown }): t is { installationId: number; branch: string; repositoryFullName: string } {
return typeof t.installationId === 'number' && t.installationId > 0 && typeof t.branch === 'string' && t.branch.length > 0 && typeof t.repositoryFullName === 'string' && t.repositoryFullName.length > 0
} Try / catch
try {
await materializePlugin({ connectorTargetId })
} catch (e) {
if (e instanceof PluginArchRouteFailure && e.code === 'invalid_github_materialization_context') {
await restartGithubConnectorInstallFlow() // repopulate installationId/branch/repo
} else throw e
} Prevention
- Always complete the GitHub App install before creating targets
- Validate targetConfig fields (branch, repositoryFullName) at save time
- Never hand-edit connector instance/target JSON; use the API flows
When it happens
Trigger: Materializing plugin code from a GitHub connector where the GitHub App was never installed (no installationId in instanceConfigJson), the target config omits `branch`, or repositoryFullName/remoteId is empty or misconfigured.
Common situations: Partial connector target setup: repo selected but branch never saved; App uninstalled from the org leaving stale instance config; manual DB edits dropping remoteId; connecting a target before completing the GitHub install callback.
Related errors
- github_connector_account_required
- t("providers.no_providers_available")
- Sign in to OpenWork Cloud and choose an organization first.
- `${provider.name} does not have a stored organization creden
- plugin_ref_not_found
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/5a0f717d53c915e1.
Report an issue: GitHub.