{"record":{"id":"c74d0fc9ddf57cb1","repo":"wagoodman/dive","slug":"failed-to-read-ci-config-file-s-w","errorCode":null,"errorMessage":"failed to read CI config file %s: %w","messagePattern":"failed to read CI config file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/dive/cli/internal/options/ci.go","lineNumber":55,"sourceCode":"func (c *CI) AddFlags(flags clio.FlagSet) {\n\tflags.BoolVarP(&c.Enabled, \"ci\", \"\", \"skip the interactive TUI and validate against CI rules (same as env var CI=true)\")\n\tflags.StringVarP(&c.ConfigPath, \"ci-config\", \"\", \"if CI=true in the environment, use the given yaml to drive validation rules.\")\n}\n\nfunc (c *CI) PostLoad() error {\n\tenabledFromEnv := truthy(os.Getenv(\"CI\"))\n\tif !c.Enabled && enabledFromEnv {\n\t\tc.Enabled = true\n\t}\n\n\tif c.ConfigPath != \"\" {\n\t\tif fileExists(c.ConfigPath) {\n\t\t\t// if a config file is provided, load it and override any values provided in the application config.\n\t\t\t// If we're hitting this case we should pretend that only the config file was provided and applied\n\t\t\t// on top of the default config values.\n\t\t\tyamlFile, err := os.ReadFile(c.ConfigPath)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to read CI config file %s: %w\", c.ConfigPath, err)\n\t\t\t}\n\t\t\tdef := DefaultCIRules()\n\t\t\tr := legacyRuleFile{\n\t\t\t\tLowestEfficiencyThresholdString: def.LowestEfficiencyThresholdString,\n\t\t\t\tHighestWastedBytesString:        def.HighestWastedBytesString,\n\t\t\t\tHighestUserWastedPercentString:  def.HighestUserWastedPercentString,\n\t\t\t}\n\t\t\twrapper := struct {\n\t\t\t\tRules *legacyRuleFile `yaml:\"rules\"`\n\t\t\t}{\n\t\t\t\tRules: &r,\n\t\t\t}\n\t\t\tif err := yaml.Unmarshal(yamlFile, &wrapper); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to unmarshal CI config file %s: %w\", c.ConfigPath, err)\n\t\t\t}\n\t\t\t// TODO: should this be a deprecated use warning in the future?\n\t\t\tc.Rules = CIRules{\n\t\t\t\tLowestEfficiencyThresholdString: r.LowestEfficiencyThresholdString,","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/wagoodman/dive/blob/d6c691947f8fda635c952a17ee3b7555379d58f0/cmd/dive/cli/internal/options/ci.go#L37-L73","documentation":"Thrown while loading the CI rules file when os.ReadFile on the user-supplied --ci-config path fails after fileExists() reported it present. The %w preserves the OS error. It only fires when ConfigPath is non-empty and the file exists at check time, so failures are typically transient or permission-related.","triggerScenarios":"Passing --ci-config <path> where the file exists but cannot be opened: permission denied (mode 000, wrong owner), a race where the file is deleted between the stat and read, or a symlink pointing to an unreadable target.","commonSituations":"CI jobs where the rules file is generated by a prior step with restrictive permissions; Docker volume-mounted configs owned by a different UID; TOCTOU deletion in shared workspaces.","solutions":["Inspect the wrapped error for the exact OS cause ('permission denied', 'no such file or directory').","Fix permissions: chmod 644 <path> and ensure the running user owns or can read it.","If the file is generated earlier in the pipeline, verify that step succeeded before invoking dive.","Remove the --ci-config flag to fall back to the built-in default CI rules if the file is optional."],"exampleFix":"# before\nchmod 600 ci-rules.yaml && sudo -u nobody dive image --ci --ci-config ci-rules.yaml  # read fails\n\n# after\nchmod 644 ci-rules.yaml && dive image --ci --ci-config ci-rules.yaml","handlingStrategy":"validation","validationCode":"// wrapper check before invoking dive\nif cfgPath != \"\" {\n    if _, err := os.ReadFile(cfgPath); err != nil {\n        return fmt.Errorf(\"ci config unreadable, fix perms or drop flag: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate CI rule files with 0644 permissions in pipelines.","Verify the prior pipeline step that writes the rules file succeeded.","Treat a missing/unreadable optional rules file as 'drop --ci-config' rather than fail."],"tags":["dive","ci","yaml","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"d6c691947f8fda635c952a17ee3b7555379d58f0","analyzedAt":"2026-08-15T09:42:35.293Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}