gohugoio/hugo · error

target path "%s" exists but is not a directory

Error message

target path "%s" exists but is not a directory

What it means

Returned by `hugo import jekyll` when the given target path already exists but is a regular file rather than a directory (commands/import.go:164-167). The importer needs to scaffold a Hugo project tree (layouts/, content/, static/, …) inside the target, which is impossible if the path is occupied by a file, so it aborts before touching anything.

Source

Thrown at commands/import.go:166

			if entry.IsDir() {
				subDir := filepath.Join(jekyllRoot, entry.Name())
				if isPostDir, hasAnyPostInDir := c.retrieveJekyllPostDir(fs, subDir); isPostDir {
					postDirs[entry.Name()] = hasAnyPostInDir
					if hasAnyPostInDir {
						hasAnyPost = true
					}
				}
			}
		}
	}
	return postDirs, hasAnyPost
}

func (c *importCommand) createProjectFromJekyll(jekyllRoot, targetDir string, jekyllPostDirs map[string]bool) error {
	fs := &afero.OsFs{}
	if exists, _ := helpers.Exists(targetDir, fs); exists {
		if isDir, _ := helpers.IsDir(targetDir, fs); !isDir {
			return errors.New("target path \"" + targetDir + "\" exists but is not a directory")
		}

		isEmpty, _ := helpers.IsEmpty(targetDir, fs)

		if !isEmpty && !c.force {
			return errors.New("target path \"" + targetDir + "\" exists and is not empty")
		}
	}

	jekyllConfig := c.loadJekyllConfig(fs, jekyllRoot)

	mkdir(targetDir, "layouts")
	mkdir(targetDir, "content")
	mkdir(targetDir, "archetypes")
	mkdir(targetDir, "static")
	mkdir(targetDir, "data")
	mkdir(targetDir, "themes")

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Verify the second argument: `ls -l <target>` — if it's a file you didn't intend, choose a different target directory name.
  2. If the file is disposable, remove it (`rm <target>`) and re-run the import.
  3. Point the import at a fresh, non-existent path (Hugo will create the directory tree).

Example fix

# before
hugo import jekyll ./old-blog ./site   # ./site is a file
# after
rm ./site && hugo import jekyll ./old-blog ./site
Defensive patterns

Strategy: validation

Validate before calling

if info, err := os.Stat(target); err == nil && !info.IsDir() {
    return fmt.Errorf("%q exists and is a file; choose another target or remove it", target)
}

Type guard

func isDir(path string) bool {
    info, err := os.Stat(path)
    return err == nil && info.IsDir()
}

Prevention

When it happens

Trigger: Running `hugo import jekyll <jekyllRoot> <target>` where <target> resolves to an existing regular file — e.g. `hugo import jekyll ./blog ./site` when `./site` is a file, or accidentally passing a filename (like a config file) as the second positional argument.

Common situations: Swapped or mistyped positional arguments (source and target reversed, or a file path pasted as target); a leftover file with the intended project name; scripts that previously `touch`ed the target path.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/86091413e8ad1876.json. Report an issue: GitHub ↗.