{"record":{"id":"dc6652e615392b22","repo":"fluent/fluentd","slug":"out-secondary-file-basename-or-directory-has-an-i","errorCode":null,"errorMessage":"out_secondary_file: basename or directory has an incompatible placeholder, remove time formats, like `%Y%m%d`, from basename or directory","messagePattern":"out_secondary_file: basename or directory has an incompatible placeholder, remove time formats, like `%Y%m(.+?)`, from basename or directory","errorType":"validation","errorClass":"Fluent::ConfigError","httpStatus":null,"severity":"error","filePath":"lib/fluent/plugin/out_secondary_file.rb","lineNumber":98,"sourceCode":"          }\n        when :gzip\n          File.open(path, \"ab\", @file_perm) {|f|\n            f.flock(File::LOCK_EX)\n            gz = Zlib::GzipWriter.new(f)\n            chunk.write_to(gz)\n            gz.close\n          }\n        end\n      end\n    end\n\n    private\n\n    def validate_compatible_with_primary_buffer!(path_without_suffix)\n      placeholders = path_without_suffix.scan(PLACEHOLDER_REGEX).flat_map(&:first) # to trim suffix [\\d+]\n\n      if !@chunk_key_time && has_time_format?(path_without_suffix)\n        raise Fluent::ConfigError, \"out_secondary_file: basename or directory has an incompatible placeholder, remove time formats, like `%Y%m%d`, from basename or directory\"\n      end\n\n      if !@chunk_key_tag && (ph = placeholders.find { |placeholder| placeholder.match?(/tag(\\[\\d+\\])?/) })\n        raise Fluent::ConfigError, \"out_secondary_file: basename or directory has an incompatible placeholder #{ph}, remove tag placeholder, like `${tag}`, from basename or directory\"\n      end\n\n      vars = placeholders.reject { |placeholder| placeholder.match?(/tag(\\[\\d+\\])?/) || (placeholder == 'chunk_id') }\n\n      if ph = vars.find { |v| !@chunk_keys.include?(v) }\n        raise Fluent::ConfigError, \"out_secondary_file: basename or directory has an incompatible placeholder #{ph}, remove variable placeholder, like `${varname}`, from basename or directory\"\n      end\n    end\n\n    def has_time_format?(str)\n      str != Time.now.strftime(str)\n    end\n\n    def generate_path(path_without_suffix)","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/fluent/fluentd/blob/dd45c6e18dc7be33b5e5a0f0767bf46307ff5626/lib/fluent/plugin/out_secondary_file.rb#L80-L116","documentation":"SecondaryFileOutput#configure validates its output path against the PRIMARY buffer's chunk keys. If the primary <buffer> has no `time` chunk key (@chunk_key_time false) but the directory/basename string contains strftime directives (detected by has_time_format?: the string changes when run through Time.now.strftime), this Fluent::ConfigError fires. The secondary writes chunks the primary already queued, and without a time chunk key there is no time value to expand %Y%m%d-style placeholders with.","triggerScenarios":"`<buffer>` or `<buffer tag>` (no `time` key) combined with a secondary_file path containing time formats, e.g. `directory /var/log/dump/%Y%m%d` or `basename dump.%Y%m%d.bin`. Any literal %Y/%m/%d/%H anywhere in the path triggers it, not just ${time} placeholders.","commonSituations":"Copying date-partitioned paths from out_file configs; adding time-based directory layout to the secondary without switching the primary to `<buffer time>`; a basename that happens to contain a %-escape from a templating system.","solutions":["Add the time key to the primary buffer: `<buffer time>` (usually `<buffer time, tag>`) with an appropriate `timekey`, so chunks carry the time needed to expand the format","Or remove the time formats from directory/basename and use a flat path","Confirm with `fluentd --dry-run` — this is caught at configure time"],"exampleFix":"# before\n<match **>\n  @type forward\n  <buffer tag>          # no time chunk key\n    ... \n  </buffer>\n  <secondary>\n    @type secondary_file\n    directory /var/log/dump/%Y%m%d\n  </secondary>\n</match>\n\n# after\n<match **>\n  @type forward\n  <buffer time, tag>\n    timekey 1d\n  </buffer>\n  <secondary>\n    @type secondary_file\n    directory /var/log/dump/%Y%m%d\n  </secondary>\n</match>","handlingStrategy":"validation","validationCode":"# Check: time formats in the secondary path require a time chunk key in the primary buffer\nbuffer = match_element.elements.find { |e| e.name == 'buffer' }\nkeys = buffer && buffer.arg.to_s.split(',').map(&:strip)\nhas_time_key = keys && keys.include?('time')\npath = File.join(directory, basename || 'dump.bin')\nraise 'time format in path but primary buffer has no time key' if !has_time_key && path != Time.now.strftime(path)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a mental checklist: %Y/%m/%d in secondary path ⇒ primary must declare `<buffer ... time>` with a timekey","Beware stray %-escapes in basenames from templating — has_time_format? triggers on any strftime directive","Dry-run secondary_file configs after ANY change to the primary buffer's chunk keys"],"tags":["fluentd","secondary-file","buffer","placeholder","time-format","configuration"],"backgroundTag":"buffer-key-placeholder-mismatch","analyzedSha":"dd45c6e18dc7be33b5e5a0f0767bf46307ff5626","analyzedAt":"2026-08-21T16:22:07.332Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}