{"record":{"id":"52fd439ef3c82451","repo":"kovidgoyal/kitty","slug":"cannot-call-createdelta-before-loading-a-signatu","errorCode":null,"errorMessage":"Cannot call CreateDelta() before loading a signature","messagePattern":"Cannot call CreateDelta\\(\\) before loading a signature","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/rsync/api.go","lineNumber":236,"sourceCode":"\t\t\treturn io.EOF\n\t\tcase nil:\n\t\t\tbl.Serialize(b[:BlockHashSize])\n\t\t\t_, err = output.Write(b[:BlockHashSize])\n\t\t\treturn err\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// Create a serialized delta based on the previously loaded signature\nfunc (self *Differ) CreateDelta(src io.Reader, output io.Writer) func() error {\n\tif err := self.FinishSignatureData(); err != nil {\n\t\treturn func() error { return err }\n\t}\n\tif self.signature == nil {\n\t\treturn func() error {\n\t\t\treturn fmt.Errorf(\"Cannot call CreateDelta() before loading a signature\")\n\t\t}\n\t}\n\treturn self.rsync.CreateDiff(src, self.signature, output)\n}\n\nfunc (self *Differ) BlockSize() int {\n\treturn self.rsync.BlockSize\n}\n\n// Add more external signature data\nfunc (self *Differ) AddSignatureData(data []byte) (err error) {\n\tself.unconsumed_signature_data = append(self.unconsumed_signature_data, data...)\n\tif !self.rsync.HasHasher() {\n\t\tconsumed, err := self.read_signature_header(self.unconsumed_signature_data)\n\t\tif err != nil {\n\t\t\tif consumed < 0 {\n\t\t\t\treturn nil\n\t\t\t}","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/tools/rsync/api.go#L218-L254","documentation":"CreateDelta requires a signature to have been loaded first. FinishSignatureData succeeded but self.signature is nil, meaning header-only data with zero blocks was processed, so there is nothing to diff against.","triggerScenarios":"Calling CreateDelta after AddSignatureData consumed only a valid header (empty file signature) — signature slice stays nil — or calling CreateDelta before any signature data at all on a path where FinishSignatureData passes.","commonSituations":"Diffing against an empty source whose signature contains only the header, or API misuse where CreateDelta is called without a prior signature load.","solutions":["Generate a real signature from a non-empty source before creating a delta","Handle the empty-source case separately rather than calling CreateDelta","Verify AddSignatureData received block data, not just the header"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if differ.BlockSize() == 0 || signatureBlockCount == 0 { skip CreateDelta; nothing to diff }","typeGuard":"func canCreateDelta(d *rsync.Differ) bool { return d.BlockSize() > 0 }","tryCatchPattern":null,"preventionTips":["Load a full signature (header + blocks) before CreateDelta","Handle empty sources as a copy operation instead of a diff"],"tags":["rsync","api-misuse","ordering"],"backgroundTag":"api-call-order","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}