temporalio/temporal · error
failed to parse visibility filename %s
Error message
failed to parse visibility filename %s
What it means
sortAndFilterFiles in the filestore visibility archiver parses archived visibility record filenames of the form <closeTime>_<hashedRunID>_<ext>, splitting on '_' and '.' and requiring exactly 3 pieces. If a filename does not split into 3 fields, it returns 'failed to parse visibility filename %s'. This guards against foreign or corrupted files in the archive directory.
Source
Thrown at common/archiver/filestore/visibility_archiver.go:262
return validateDirPath((URI.Path()))
}
type parsedVisFilename struct {
name string
closeTime time.Time
hashedRunID string
}
// sortAndFilterFiles sort visibility record file names based on close timestamp (desc) and use hashed runID to break ties.
// if a nextPageToken is give, it only returns filenames that have a smaller close timestamp
func sortAndFilterFiles(filenames []string, token *queryVisibilityToken) ([]string, error) {
var parsedFilenames []*parsedVisFilename
for _, name := range filenames {
pieces := strings.FieldsFunc(name, func(r rune) bool {
return r == '_' || r == '.'
})
if len(pieces) != 3 {
return nil, fmt.Errorf("failed to parse visibility filename %s", name)
}
closeTime, err := strconv.ParseInt(pieces[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse visibility filename %s", name)
}
parsedFilenames = append(parsedFilenames, &parsedVisFilename{
name: name,
closeTime: timestamp.UnixOrZeroTime(closeTime),
hashedRunID: pieces[1],
})
}
sort.Slice(parsedFilenames, func(i, j int) bool {
if parsedFilenames[i].closeTime.Equal(parsedFilenames[j].closeTime) {
return parsedFilenames[i].hashedRunID > parsedFilenames[j].hashedRunID
}
return parsedFilenames[i].closeTime.After(parsedFilenames[j].closeTime)View on GitHub (pinned to bde624efd1)
Solutions
- Remove or move out the non-conforming file from the visibility archive directory
- Rename the file to the canonical '<closeTimeUnixNano>_<hashedRunID>_<ext>' format if its data is valid
- Verify all files in the directory were written by the same archiver version/format
Example fix
// before archive dir: 1727123456789012345_a1b2c3_visibility notes.txt <- stray file // after mv notes.txt /var/log/archive-notes/ # keep archive dir only for visibility files
Defensive patterns
Strategy: validation
Validate before calling
for _, name := range filenames {
if len(strings.FieldsFunc(name, func(r rune) bool { return r == '_' || r == '.' })) != 3 {
// clean or quarantine before querying
}
} Type guard
func isValidVisFilename(name string) bool { return len(strings.FieldsFunc(name, func(r rune) bool { return r == '_' || r == '.' })) == 3 } Try / catch
resp, err := client.ArchiveQuery(ctx, req)
if err != nil {
if strings.Contains(err.Error(), "failed to parse visibility filename") {
logger.Warn("archive dir contains foreign file", tag.Error(err))
}
return err
} Prevention
- Keep the archive directory dedicated to visibility files — no manual drops
- Monitor the archive directory for unexpected files
- Keep the archiver version uniform; don't mix filename formats
When it happens
Trigger: Querying the file-based visibility archiver when the archive directory contains a file whose name does not have exactly two underscores and one dot-separated extension segment (e.g. 'run_failed.txt' or a manually placed file).
Common situations: Operators placing logs, temp files, or backups into the archive directory; a different archiver format version writing different filenames; or partial writes leaving truncated names.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unknown workflow close status: %s
- unknown filter name: %s
- only operation = is support for %s
- where expression is nil
- invalid filter name: %s
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/cf0b5bb1f91b3d73.
Report an issue: GitHub.