hcengineering/platform · error
Failed to create channel for ${normalizedEmail} in space ${s
Error message
Failed to create channel for ${normalizedEmail} in space ${space}: ${err instanceof Error ? err.message : String(err)} What it means
fetchOrCreateChannel looks up a mail channel for a normalized email within a space, and if absent creates one. When the creation itself fails (the wrapped err — DB errors, permission issues, invalid space/email, transient conflicts), the original error is removed from cache and rethrown wrapped in this descriptive Error naming the email and space.
Source
Thrown at services/mail/mail-common/src/channel.ts:104
if (channel != null) {
this.ctx.info('Using existing channel', { me: normalizedEmail, space, channel: channel._id })
return channel._id as Ref<Card>
}
return await this.createNewChannel(space, participants, normalizedEmail, personId)
} catch (err) {
this.ctx.error('Failed to create channel', {
me: normalizedEmail,
space,
workspace: this.workspace,
error: err instanceof Error ? err.message : String(err)
})
// Remove failed lookup from cache
this.cache.delete(`${space}:${normalizedEmail}`)
throw new Error(
`Failed to create channel for ${normalizedEmail} in space ${space}: ${err instanceof Error ? err.message : String(err)}`
)
}
}
private async createNewChannel (
space: Ref<Space>,
participants: PersonId[],
email: string,
personId: PersonId
): Promise<Ref<Card>> {
const normalizedEmail = normalizeEmail(email)
const mutexKey = `channel:${this.workspace}:${space}:${normalizedEmail}`
const releaseLock = await createMutex.lock(mutexKey)
try {
// Double-check that channel doesn't exist after acquiring lock
const existingChannel = await this.client.findOne(mail.tag.MailThread, { title: normalizedEmail })View on GitHub (pinned to 63e28dc964)
Solutions
- Inspect the wrapped err.message (embedded in this message) to find the root cause — it names the underlying failure.
- Verify the space exists and the email domain/address is valid before calling getOrCreateChannel.
- Retry on transient DB errors — the failed cache entry is already evicted so a retry re-attempts creation.
- Add a uniqueness-safe retry or upsert in createNewChannel to tolerate concurrent creation races.
Example fix
// before
const channel = await getOrCreateChannel(ctx, space, email) // throws on race
// after
let channel
try {
channel = await getOrCreateChannel(ctx, space, email)
} catch (err) {
await new Promise(r => setTimeout(r, 200))
channel = await getOrCreateChannel(ctx, space, email)
} Defensive patterns
Strategy: retry
Validate before calling
const spaceExists = await findSpace(ctx, space)
if (spaceExists === undefined) {
throw new Error(`Space ${space} does not exist; not attempting channel creation for ${email}`)
} Type guard
null
Try / catch
try {
channel = await getOrCreateChannel(ctx, space, email)
} catch (err) {
if (err.message.startsWith('Failed to create channel')) {
console.error(`Channel creation failed (root cause: ${err.message}); retrying once`)
await sleep(200)
channel = await getOrCreateChannel(ctx, space, email)
} else throw err
} Prevention
- Verify the space exists before mail ingestion routes to it.
- Retry transient failures — the failed lookup is evicted from cache, so retries re-attempt creation.
- Make channel creation idempotent to survive concurrent deliveries of the same email.
When it happens
Trigger: Calling getOrCreateChannel where the underlying createNewChannel/factory call throws — e.g. the space doesn't exist, database connectivity failure, or a concurrent request racing to create the same channel.
Common situations: Inbound mail processing for an address whose space was deleted; transient DB outages during mail ingestion; duplicate concurrent webhook deliveries creating the same channel simultaneously; misconfigured mail routing producing emails for non-existent spaces.
Related errors
- Failed to ensure person exists for email: ${email}
- Peer value already exists
- Failed to load server config
- getDisplayMedia not supported
- No screen access granted
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/5db257e341efec57.
Report an issue: GitHub.