kubernetes/kops · error
unable to read template: %s, error: %s
Error message
unable to read template: %s, error: %s
What it means
Returned by RunToolBoxTemplate when os.ReadFile fails on a template file that expandFiles already listed. The glob expansion succeeded but the individual template file could not be read — usually a permission problem, the file disappearing between listing and read, or a dangling symlink. The template path and underlying OS error are included in the message.
Source
Thrown at cmd/kops/toolbox_template.go:179
if err != nil {
return fmt.Errorf("unable to read snippet: %s, error: %s", j, err)
}
snippets[path.Base(j)] = string(content)
}
}
channel, err := kopsapi.LoadChannel(f.VFSContext(), options.channel)
if err != nil {
return fmt.Errorf("error loading channel %q: %v", options.channel, err)
}
// @step: render each of the templates, splitting on the documents
r := templater.NewTemplater(channel)
var documents []string
for _, x := range templates {
content, err := os.ReadFile(x)
if err != nil {
return fmt.Errorf("unable to read template: %s, error: %s", x, err)
}
rendered, err := r.Render(string(content), context, snippets, options.failOnMissing)
if err != nil {
return fmt.Errorf("unable to render template: %s, error: %s", x, err)
}
// @check if the content is zero ignore it
if len(rendered) <= 0 {
continue
}
if !options.formatYAML {
documents = append(documents, strings.Split(rendered, "---\n")...)
continue
}
for _, x := range strings.Split(rendered, "---\n") {
var data map[string]interface{}View on GitHub (pinned to 4c8573c808)
Solutions
- Check permissions on the file named in the error (ls -l) and grant read access
- Confirm the file exists and isn't a broken symlink: ls -lL <file>
- Ensure no concurrent job deletes/moves files in the templates directory during the run
- Run the command as a user with read access to all template files
Example fix
// before -rw------- ./templates/cluster.yaml (owned by ci-user, run as deploy-user) // after chmod a+r ./templates/cluster.yaml
Defensive patterns
Strategy: try-catch
Validate before calling
matches, _ := filepath.Glob(templateDir)
for _, f := range matches {
fi, err := os.Stat(f)
if err != nil || fi.IsDir() || fi.Mode().Perm()&0o400 == 0 {
return fmt.Errorf("template %s unreadable", f)
}
} Try / catch
content, err := os.ReadFile(templateFile)
if err != nil {
switch {
case errors.Is(err, os.ErrPermission):
return fmt.Errorf("grant read access to %s", templateFile)
case errors.Is(err, os.ErrNotExist):
return fmt.Errorf("template %s removed since glob expansion", templateFile)
default:
return err
}
} Prevention
- Keep template files readable (0644) and owned by the user running kops
- Do not mutate template directories concurrently with rendering
- Verify symlinks in template repos point to existing checkouts
When it happens
Trigger: A template file matched by --template-path glob is unreadable: permissions deny read, file deleted between expandFiles and ReadFile (concurrent build cleanup), broken symlink, or the path points at a special/unreadable file.
Common situations: Templates with 0600 modes owned by another user; running as a different user in CI than the file owner; tmpdirs or generated template directories being wiped mid-run; symlinked template repos pointing at missing checkouts.
Related errors
- unable to expand the template: %s, error: %s
- unable to expand the snippets: %s, error: %s
- unable to read snippet: %s, error: %s
- creating directory %q: %w
- creating file %q: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/356bbbd7990dc480.
Report an issue: GitHub.