flipped-aurora/gin-vue-admin · error

parent plugin is not a directory

Error message

parent plugin is not a directory

What it means

When installing a sub-plugin under a parent plugin, the installer resolves the parent's directory on disk and stats it. If the parent path exists but is a file (or symlink to a file) rather than a directory, it cannot host a subPlugin folder, so this error is thrown.

Source

Thrown at server/service/system/auto_code_plugin.go:325

	}
	return archive, nil
}

func pluginInstallRoot(component, parentPlugin string) (string, error) {
	root, err := utils.JoinWithinRoot(global.GVA_CONFIG.AutoCode.Root, component, "plugin")
	if err != nil || parentPlugin == "" {
		return root, err
	}
	parentPath, err := utils.JoinWithinRoot(root, parentPlugin)
	if err != nil {
		return "", err
	}
	info, err := os.Stat(parentPath)
	if err != nil {
		return "", errors.Wrap(err, "parent plugin does not exist")
	}
	if !info.IsDir() {
		return "", errors.New("parent plugin is not a directory")
	}
	return utils.JoinWithinRoot(parentPath, "subPlugin")
}

func ensurePluginTargetAvailable(root, pluginName string) error {
	target, err := utils.JoinWithinRoot(root, pluginName)
	if err != nil {
		return err
	}
	if _, err = os.Stat(target); err == nil {
		return errors.New("plugin already exists")
	} else if !os.IsNotExist(err) {
		return err
	}
	return nil
}

func copyPluginArchive(sourceRoot, destinationRoot string) error {

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Inspect the parent plugin path on disk and remove or rename the stray file that occupies the plugin name.
  2. Re-clone or restore the parent plugin directory from source so it exists as a proper directory.
  3. Verify the parentPlugin name passed to the install API is spelled correctly (exact case).
  4. Ensure the plugin root directory in AutoCode.Server config points to the intended component tree.

Example fix

// before (on disk)
server/plugin/parent-plugin   <- plain file
// after
mkdir server/plugin/parent-plugin
# restore plugin contents (plugin.go, etc.)
server/plugin/parent-plugin/plugin.go
Defensive patterns

Strategy: validation

Validate before calling

const st = fs.statSync(path.join(serverPluginRoot, parentPlugin))
if (!st.isDirectory()) throw new Error(`${parentPlugin} exists but is not a directory`)

Try / catch

try {
  await installSubPlugin(parent, child)
} catch (e) {
  if (e.message.includes('not a directory')) {
    showHint('Parent plugin path is occupied by a file; remove or rename it.')
  } else { throw e }
}

Prevention

When it happens

Trigger: Calling the sub-plugin install API with a parentPlugin name that collides with a regular file inside the component's plugin root (e.g. a stray `foo.zip` or a file named `foo` where the plugin directory should be).

Common situations: Leftover files accidentally named like a plugin; a plugin that was replaced by a tarball/zip left in place; path case-sensitivity mismatch causing Stat to hit a different file; corrupted checkout where the plugin directory was overwritten by a file.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/2602d40cd2c38264. Report an issue: GitHub.