discordjs/discord.js · error · DiscordjsError
GuildChannelOrphan
GuildChannelOrphan
Error message
GuildChannelOrphan
What it means
GuildChannelOrphan is thrown by GuildChannel#lockPermissions when the channel has no parent — there is no parent channel from which to copy permission overwrites. 'Orphan' means the channel is not attached to a category (or the parent is uncached/unresolvable), so locking permissions from a parent is impossible.
Source
Thrown at packages/discord.js/src/structures/GuildChannel.js:286
const basePermissions = new PermissionsBitField([role.permissions, role.guild.roles.everyone.permissions]);
const everyoneOverwrites = this.permissionOverwrites.cache.get(this.guild.id);
const roleOverwrites = this.permissionOverwrites.cache.get(role.id);
return basePermissions
.remove(everyoneOverwrites?.deny ?? PermissionsBitField.DefaultBit)
.add(everyoneOverwrites?.allow ?? PermissionsBitField.DefaultBit)
.remove(roleOverwrites?.deny ?? PermissionsBitField.DefaultBit)
.add(roleOverwrites?.allow ?? PermissionsBitField.DefaultBit)
.freeze();
}
/**
* Locks in the permission overwrites from the parent channel.
*
* @returns {Promise<GuildChannel>}
*/
async lockPermissions() {
if (!this.parent) throw new DiscordjsError(ErrorCodes.GuildChannelOrphan);
const permissionOverwrites = this.parent.permissionOverwrites.cache.map(overwrite => overwrite.toJSON());
return this.edit({ permissionOverwrites });
}
/**
* A collection of cached members of this channel, mapped by their ids.
* Members that can view this channel, if the channel is text-based.
* Members in the channel, if the channel is voice-based.
*
* @type {Collection<Snowflake, GuildMember>}
* @readonly
*/
get members() {
return this.guild.members.cache.filter(member =>
this.permissionsFor(member).has(PermissionFlagsBits.ViewChannel, false),
);
}
View on GitHub (pinned to a81ed8a306)
Solutions
- Check channel.parent before calling: `if (!channel.parent) return;` and skip or create a category first
- Assign the channel to a category (channel.setParent(categoryId, { lockPermissions: true })) instead of manually locking
- If the parent may be uncached, fetch it: `const parent = await channel.guild.channels.fetch(channel.parentId)` and copy its permissionOverwrites manually via channel.edit({ permissionOverwrites: ... })
- Guard in bulk-sync loops: only call lockPermissions for channels where parentId is set
Example fix
// before await channel.lockPermissions(); // throws when channel has no category // after if (!channel.parent) return; await channel.lockPermissions();
Defensive patterns
Strategy: validation
Validate before calling
if (!channel.parent) return; // orphan: nothing to lock from await channel.lockPermissions();
Type guard
function hasParentChannel(channel) {
return channel.parent != null || typeof channel.parentId === 'string';
} Try / catch
try {
await channel.lockPermissions();
} catch (err) {
if (err.name === 'DiscordjsError' && err.message.includes('GuildChannelOrphan')) {
return; // channel is not in a category; skip
}
throw err;
} Prevention
- Skip lockPermissions for channels without parentId
- Prefer channel.setParent(id, { lockPermissions: true }) when moving channels
- Fetch/cache the parent channel before permission sync routines
- Account for DM/group channels lacking guild parents in shared code paths
When it happens
Trigger: Calling channel.lockPermissions() on a channel whose parent is null — a top-level channel not inside any category, or a channel whose parent exists on Discord's side but isn't cached/resolved by the client yet.
Common situations: Syncing permissions of a channel programmatically when the channel was moved out of its category; running lockPermissions in setup scripts before the parent channel is fetched/cached; assuming every channel has a parent; comparing with the Discord UI 'Sync Permissions' which is disabled for non-category children.
Related errors
AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30).
Data as JSON: /api/errors/1320a7926507aa3f.
Report an issue: GitHub.