iflytek/astron-agent · error

credential file must be a regular non-symbolic-link file

Error message

credential file must be a regular non-symbolic-link file

What it means

readCredentialFile requires the credential file to be a regular file and not a symbolic link; Stat()'s mode is checked and non-regular files (symlink, directory, fifo, device) are rejected. This prevents symlink-based attacks and accidental misconfiguration of the credential path.

Solutions

  1. Replace the symlink with a real regular file (copy the content, do not link)
  2. Mount the credential directly (e.g. Kubernetes secret volume files are fine — use the resolved path under ..data only via the mount)
  3. Verify with `stat -c %F <path>` that it reports 'regular file'

Example fix

# before
ln -s /etc/tenant/secret.pem /creds/TENANT_SECRET
# after
cp /etc/tenant/secret.pem /creds/TENANT_SECRET && chmod 600 /creds/TENANT_SECRET
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Lstat(path)
if err != nil || info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
    return fmt.Errorf("%s must be a regular file, not a symlink", path)
}

Try / catch

if err := config.ValidateCredentialPaths(map[string]string{"TENANT_KEY_FILE": keyPath, "TENANT_SECRET_FILE": secretPath}); err != nil {
    logger.Fatal("fix credential mounts: only regular files allowed")
}

Prevention

When it happens

Trigger: credentialFromEnvironmentOrFile resolves a *_FILE env var to a path; the opened file's Stat().Mode() is not IsRegular() — e.g. the path is a symlink (including an attacked symlink to /etc/shadow) or a named pipe.

Common situations: Operator symlinked a credential file for convenience instead of mounting it directly, a tmpfs/fifo was used, or a container secret mount created an intermediate symlink.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/02bef6783211570c. Report an issue: GitHub.

Appendix: source

Thrown at core/tenant/config/bootstrap_credentials.go:120

	}
	return value, nil
}

func readCredentialFile(fileName string) (string, error) {
	file, err := openCredentialFileNoFollow(fileName)
	if err != nil {
		return "", err
	}
	defer func() {
		_ = file.Close()
	}()

	openedInfo, err := file.Stat()
	if err != nil {
		return "", errors.New("credential file cannot be inspected")
	}
	if !openedInfo.Mode().IsRegular() {
		return "", errors.New("credential file must be a regular non-symbolic-link file")
	}
	if openedInfo.Size() > maxCredentialFileBytes {
		return "", errors.New("credential file is too large")
	}

	data, err := io.ReadAll(io.LimitReader(file, maxCredentialFileBytes+1))
	if err != nil {
		return "", errors.New("credential file cannot be read")
	}
	if len(data) > maxCredentialFileBytes {
		return "", errors.New("credential file is too large")
	}
	return strings.TrimSpace(string(data)), nil
}

func validateCredential(name, value string) error {
	length := utf8.RuneCountInString(value)
	if !utf8.ValidString(value) || length < tenantCredentialMinLength || length > tenantCredentialMaxLength {

View on GitHub (pinned to 5e758547a8)