{"record":{"id":"c54b463488182584","repo":"t8y2/dbx","slug":"oracle-tns-include-depth-exceeds-8-files","errorCode":null,"errorMessage":"Oracle TNS include depth exceeds 8 files","messagePattern":"Oracle TNS include depth exceeds 8 files","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/oracle-go/tns.go","lineNumber":104,"sourceCode":"func oracleTNSNamesPath(tnsAdmin string) (string, error) {\n\tpath := filepath.Clean(strings.TrimSpace(tnsAdmin))\n\tinfo, err := os.Stat(path)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"Oracle TNS_ADMIN directory is not accessible: %s\", path)\n\t}\n\tif !info.IsDir() {\n\t\treturn \"\", fmt.Errorf(\"Oracle TNS_ADMIN must be a directory containing tnsnames.ora: %s\", path)\n\t}\n\ttnsNamesPath := filepath.Join(path, \"tnsnames.ora\")\n\tif info, err := os.Stat(tnsNamesPath); err != nil || info.IsDir() {\n\t\treturn \"\", fmt.Errorf(\"Oracle tnsnames.ora was not found in TNS_ADMIN directory: %s\", path)\n\t}\n\treturn tnsNamesPath, nil\n}\n\nfunc readOracleTNSAliases(path string, visited map[string]bool, depth int) (map[string]string, error) {\n\tif depth > 8 {\n\t\treturn nil, fmt.Errorf(\"Oracle TNS include depth exceeds 8 files\")\n\t}\n\tabsolutePath, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Failed to resolve Oracle TNS file path: %w\", err)\n\t}\n\tif visited[absolutePath] {\n\t\treturn map[string]string{}, nil\n\t}\n\tvisited[absolutePath] = true\n\n\tfile, err := os.Open(absolutePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Failed to read Oracle TNS file %s: %w\", absolutePath, err)\n\t}\n\tdefer file.Close()\n\n\taliases := make(map[string]string)\n\tvar currentAliases []string","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/oracle-go/tns.go#L86-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Flatten the TNS configuration: merge the deeply nested IFILE files into fewer files so nesting stays within 8 levels","Remove unnecessary IFILE directives or point them at a single consolidated file","Check for include cycles or repeated chains (A->B->A style) and remove the redundant includes","If legitimately needing more depth, raise the depth limit in tns.go and re-test (requires modifying the library)"],"exampleFix":"# before (tnsnames.ora chain >8 deep)\nIFILE=/etc/oracle/tns_level2.ora\n# level2 -> level3 -> ... -> level10\n\n# after (consolidated)\nIFILE=/etc/oracle/tns_common.ora\n# single include holding all aliases","handlingStrategy":"validation","validationCode":"func countIFILEDepth(path string, depth int) (int, error) {\n    if depth > 8 {\n        return depth, fmt.Errorf(\"include depth exceeds 8 at %s\", path)\n    }\n    data, err := os.ReadFile(path)\n    if err != nil {\n        return depth, err\n    }\n    max := depth\n    for _, line := range strings.Split(string(data), \"\\n\") {\n        if strings.HasPrefix(strings.TrimSpace(line), \"IFILE=\") {\n            inc := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), \"IFILE=\"))\n            d, err := countIFILEDepth(inc, depth+1)\n            if err != nil {\n                return max, err\n            }\n            if d > max {\n                max = d\n            }\n        }\n    }\n    return max, nil\n}\n// call countIFILEDepth(\"/etc/oracle/tnsnames.ora\", 0) before resolving aliases","typeGuard":"func tnsDepthOK(path string) bool {\n    depth, err := countIFILEDepth(path, 0)\n    return err == nil && depth <= 8\n}","tryCatchPattern":"aliases, err := resolveOracleTNSAlias(name)\nvar depthErr *fmt.Errorf\nif err != nil && strings.Contains(err.Error(), \"include depth exceeds 8\") {\n    log.Printf(\"TNS IFILE chain too deep; flattening config: %v\", err)\n    aliases, err = resolveFromFlattenedTNS()\n}","preventionTips":["Keep TNS IFILE nesting to 1-2 levels; consolidate includes","Lint tnsnames.ora files in CI to detect deep or cyclic IFILE chains","Never commit recursive IFILE patterns (A includes B includes A)"],"tags":["oracle","tns","configuration","recursion-limit"],"backgroundTag":"tns-include-depth-exceeded","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}