beekeeper-studio/beekeeper-studio · error
Cannot delete folder "${this.name}" — move or remove its ${p
Error message
Cannot delete folder "${this.name}" — move or remove its ${pluralize('query', count, true)} first. What it means
QueryFolder.preventRemoveIfNotEmpty is a TypeORM @BeforeRemove() hook that blocks deleting a query folder that still contains favorite queries. It counts FavoriteQuery rows with the folder's queryFolderId and throws when the count is greater than zero, forcing the user to move or delete the contained queries first.
Source
Thrown at apps/studio/src/common/appdb/models/QueryFolder.ts:41
@Column({ type: 'integer', nullable: true, default: null })
@PreventMovingFolderInsideItself
parentId: Nullable<number> = null
// Do NOT initialize this to null. A null initializer becomes an own property
// that gets copied into transport objects by cls.merge(), and TypeORM treats an
// explicitly-null relation as "unset this FK", overriding the parentId column.
@ManyToOne(() => QueryFolder, { nullable: true, onDelete: 'SET NULL' })
@JoinColumn({ name: 'parentId' })
parent?: QueryFolder
@OneToMany(() => FavoriteQuery, (query) => query.queryFolder)
queries: FavoriteQuery[]
@BeforeRemove()
async preventRemoveIfNotEmpty(): Promise<void> {
const count = await FavoriteQuery.countBy({ queryFolderId: this.id })
if (count > 0) {
throw new Error(`Cannot delete folder "${this.name}" — move or remove its ${pluralize('query', count, true)} first.`)
}
}
@BeforeInsert()
@BeforeUpdate()
async preventDuplicateName(): Promise<void> {
if (!this.name) return
const where: any = {
name: this.name,
parentId: this.parentId ?? IsNull(),
}
if (this.id) where.id = Not(this.id)
const existing = await QueryFolder.findOneBy(where)
if (existing) {
throw new Error(`A folder named "${this.name}" already exists in this location.`)
}
}
}View on GitHub (pinned to 4e3e03e322)
Solutions
- Move the contained queries to another folder (update FavoriteQuery.queryFolderId) before removing the folder.
- Delete the FavoriteQuery rows in the folder first, then delete the folder.
- Catch the error in the UI and show the message so the user can empty the folder manually.
Example fix
// before
await queryFolderRepo.remove(folder);
// after
const count = await FavoriteQuery.countBy({ queryFolderId: folder.id });
if (count === 0) {
await queryFolderRepo.remove(folder);
} else {
await FavoriteQuery.update({ queryFolderId: folder.id }, { queryFolderId: otherFolder.id });
await queryFolderRepo.remove(folder);
} Defensive patterns
Strategy: validation
Validate before calling
const queryCount = await FavoriteQuery.countBy({ queryFolderId: folder.id });
if (queryCount > 0) {
throw new Error(`Move or remove ${queryCount} quer${queryCount === 1 ? 'y' : 'ies'} before deleting this folder.`);
} Try / catch
try {
await queryFolderRepo.remove(folder);
} catch (e) {
if (String(e.message).startsWith('Cannot delete folder')) {
showError(e.message); // prompt user to empty the folder first
}
} Prevention
- Count child FavoriteQuery rows before every folder delete.
- Move children to a target folder as part of the delete flow when the user confirms.
- Disable the delete action in the UI while the folder is non-empty.
When it happens
Trigger: Calling folder.remove() / repository.remove(folder) / soft cascade deletes on a QueryFolder whose id is referenced by one or more FavoriteQuery.queryFolderId rows.
Common situations: Users trying to delete a folder via sidebar context menu while it still holds saved queries; cleanup scripts deleting folder rows without inspecting children; code assuming cascade delete that is not configured on the relation.
Related errors
- Cannot delete folder "${this.name}" — move or remove its ${p
- A folder named "${this.name}" already exists in this locatio
- database path must be set for SQLite databases
- A folder named "${this.name}" already exists in this locatio
- Error adding new preset
AI-assisted analysis of beekeeper-studio/beekeeper-studio@4e3e03e322 (2026-08-31).
Data as JSON: /api/errors/df7a5476b85574b3.
Report an issue: GitHub.