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

  1. Remove or move out the non-conforming file from the visibility archive directory
  2. Rename the file to the canonical '<closeTimeUnixNano>_<hashedRunID>_<ext>' format if its data is valid
  3. 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

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

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/cf0b5bb1f91b3d73. Report an issue: GitHub.