{"id":"a732f31a9509245e","repo":"gohugoio/hugo","slug":"publish-must-provide-a-targetpath","errorCode":null,"errorMessage":"Publish: must provide a TargetPath","messagePattern":"Publish: must provide a TargetPath","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"publisher/publisher.go","lineNumber":96,"sourceCode":"\n// NewDestinationPublisher creates a new DestinationPublisher.\nfunc NewDestinationPublisher(rs *resources.Spec, outputFormats output.Formats, mediaTypes media.Types) (pub DestinationPublisher, err error) {\n\tfs := rs.BaseFs.PublishFs\n\tcfg := rs.Cfg\n\tvar classCollector *htmlElementsCollector\n\tif rs.BuildConfig().BuildStats.Enabled() {\n\t\tclassCollector = newHTMLElementsCollector(rs.BuildConfig().BuildStats)\n\t}\n\tpub = DestinationPublisher{fs: fs, htmlElementsCollector: classCollector}\n\tpub.min, err = minifiers.New(mediaTypes, outputFormats, cfg)\n\treturn\n}\n\n// Publish applies any relevant transformations and writes the file\n// to its destination, e.g. /public.\nfunc (p DestinationPublisher) Publish(d Descriptor) error {\n\tif d.TargetPath == \"\" {\n\t\treturn errors.New(\"Publish: must provide a TargetPath\")\n\t}\n\n\tsrc := d.Src\n\n\ttransformers := p.createTransformerChain(d)\n\n\tif len(transformers) != 0 {\n\t\tb := bp.GetBuffer()\n\t\tdefer bp.PutBuffer(b)\n\n\t\tif err := transformers.Apply(b, d.Src); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to process %q: %w\", d.TargetPath, err)\n\t\t}\n\n\t\t// This is now what we write to disk.\n\t\tsrc = b\n\t}\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/publisher/publisher.go#L78-L114","documentation":"DestinationPublisher.Publish writes a rendered output file to the destination filesystem (e.g. /public). The Descriptor it receives must carry a non-empty TargetPath — the relative path to write to. An empty TargetPath means there is nowhere to write, so Hugo fails fast instead of silently dropping output.","triggerScenarios":"Calling Publish with a Descriptor whose TargetPath field is the empty string. In practice this is an internal invariant: it surfaces when render hooks/output-format plumbing (or code embedding Hugo as a library) constructs a Descriptor without setting the target path.","commonSituations":"Programs embedding Hugo's publisher package directly and forgetting to set Descriptor.TargetPath; in rare cases a Hugo bug where an output format resolves to an empty permalink/path, e.g. malformed permalink config producing an empty path.","solutions":["If embedding Hugo as a library, set Descriptor.TargetPath before calling Publish.","If seen from a normal Hugo build, check permalink and outputs config for entries that could resolve to an empty path.","Report it as a Hugo bug with a minimal reproducer if config looks sane — this is an internal invariant violation."],"exampleFix":"// before\np.Publish(publisher.Descriptor{Src: r})\n// after\np.Publish(publisher.Descriptor{Src: r, TargetPath: \"index.html\", OutputFormat: f})","handlingStrategy":"validation","validationCode":"if d.TargetPath == \"\" {\n    return errors.New(\"descriptor missing TargetPath\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always populate Descriptor.TargetPath before calling Publish","Use a constructor/helper that requires the target path instead of a bare struct literal","Assert non-empty output paths in unit tests for any code building publish descriptors"],"tags":["hugo","publisher","internal-invariant"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}