t8y2/dbx · error

Oracle TNS include depth exceeds 8 files

Error message

Oracle TNS include depth exceeds 8 files

What it means

readOracleTNSAliases recursively follows IFILE includes in an Oracle tnsnames.ora file and enforces a hard limit of 8 nested include files. When the recursion depth exceeds 8, the parser stops and returns this error to prevent runaway include chains. It protects against self-referential or pathological IFILE graphs in TNS configuration.

Source

Thrown at agents/drivers/oracle-go/tns.go:104

func oracleTNSNamesPath(tnsAdmin string) (string, error) {
	path := filepath.Clean(strings.TrimSpace(tnsAdmin))
	info, err := os.Stat(path)
	if err != nil {
		return "", fmt.Errorf("Oracle TNS_ADMIN directory is not accessible: %s", path)
	}
	if !info.IsDir() {
		return "", fmt.Errorf("Oracle TNS_ADMIN must be a directory containing tnsnames.ora: %s", path)
	}
	tnsNamesPath := filepath.Join(path, "tnsnames.ora")
	if info, err := os.Stat(tnsNamesPath); err != nil || info.IsDir() {
		return "", fmt.Errorf("Oracle tnsnames.ora was not found in TNS_ADMIN directory: %s", path)
	}
	return tnsNamesPath, nil
}

func readOracleTNSAliases(path string, visited map[string]bool, depth int) (map[string]string, error) {
	if depth > 8 {
		return nil, fmt.Errorf("Oracle TNS include depth exceeds 8 files")
	}
	absolutePath, err := filepath.Abs(path)
	if err != nil {
		return nil, fmt.Errorf("Failed to resolve Oracle TNS file path: %w", err)
	}
	if visited[absolutePath] {
		return map[string]string{}, nil
	}
	visited[absolutePath] = true

	file, err := os.Open(absolutePath)
	if err != nil {
		return nil, fmt.Errorf("Failed to read Oracle TNS file %s: %w", absolutePath, err)
	}
	defer file.Close()

	aliases := make(map[string]string)
	var currentAliases []string

View on GitHub (pinned to c0390bff16)

Solutions

  1. Flatten the TNS configuration: merge the deeply nested IFILE files into fewer files so nesting stays within 8 levels
  2. Remove unnecessary IFILE directives or point them at a single consolidated file
  3. Check for include cycles or repeated chains (A->B->A style) and remove the redundant includes
  4. If legitimately needing more depth, raise the depth limit in tns.go and re-test (requires modifying the library)

Example fix

# before (tnsnames.ora chain >8 deep)
IFILE=/etc/oracle/tns_level2.ora
# level2 -> level3 -> ... -> level10

# after (consolidated)
IFILE=/etc/oracle/tns_common.ora
# single include holding all aliases
Defensive patterns

Strategy: validation

Validate before calling

func countIFILEDepth(path string, depth int) (int, error) {
    if depth > 8 {
        return depth, fmt.Errorf("include depth exceeds 8 at %s", path)
    }
    data, err := os.ReadFile(path)
    if err != nil {
        return depth, err
    }
    max := depth
    for _, line := range strings.Split(string(data), "\n") {
        if strings.HasPrefix(strings.TrimSpace(line), "IFILE=") {
            inc := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), "IFILE="))
            d, err := countIFILEDepth(inc, depth+1)
            if err != nil {
                return max, err
            }
            if d > max {
                max = d
            }
        }
    }
    return max, nil
}
// call countIFILEDepth("/etc/oracle/tnsnames.ora", 0) before resolving aliases

Type guard

func tnsDepthOK(path string) bool {
    depth, err := countIFILEDepth(path, 0)
    return err == nil && depth <= 8
}

Try / catch

aliases, err := resolveOracleTNSAlias(name)
var depthErr *fmt.Errorf
if err != nil && strings.Contains(err.Error(), "include depth exceeds 8") {
    log.Printf("TNS IFILE chain too deep; flattening config: %v", err)
    aliases, err = resolveFromFlattenedTNS()
}

Prevention

When it happens

Trigger: Calling resolveOracleTNSAlias (directly or via readOracleTNSAliases) on a tnsnames.ora whose IFILE includes nest more than 8 levels deep, e.g. file A includes B, B includes C, ... beyond the 9th file.

Common situations: Hand-edited or tool-generated tnsnames.ora files that chain IFILE directives (common in large enterprises splitting TNS entries per environment); accidentally including the same directory of files repeatedly; a symlink or include cycle that was caught by the visited-set but pushed depth past the limit.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/c54b463488182584. Report an issue: GitHub.