{"record":{"id":"407a48fbcc037f45","repo":"inancgumus/learngo","slug":"not-png","errorCode":null,"errorMessage":"not png","messagePattern":"not png","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"interfaces/16-io-compose/main.go","lineNumber":70,"sourceCode":"\tconst pngSign = \"\\x89PNG\\r\\n\\x1a\\n\"\n\tconst pngSignLen = 8\n\n\tvar memory bytes.Buffer\n\n\t// limit what copy() reads.\n\t// lr := io.LimitReader(r, pngSignLen)\n\t// if n, err = io.Copy(&memory, lr); err != nil {\n\t// return n, err\n\t// }\n\n\t// same as above. behind the scenes CopyN() calls LimitReader.\n\tif n, err = io.CopyN(&memory, r, pngSignLen); err != nil {\n\t\treturn n, err\n\t}\n\n\t// check the png signature.\n\tif !bytes.HasPrefix(memory.Bytes(), []byte(pngSign)) {\n\t\treturn n, errors.New(\"not png\")\n\t}\n\n\t// stitch the PNG signature (memory) and the response body reader together.\n\t// then copy them successively to the writer (*os.File).\n\treturn io.Copy(w, io.MultiReader(&memory, r))\n}\n","sourceCodeStart":52,"sourceCodeEnd":77,"githubUrl":"https://github.com/inancgumus/learngo/blob/3c475a78e54336c6255e925ff66b8ef4da6a2ae7/interfaces/16-io-compose/main.go#L52-L77","documentation":"transfer() reads the first pngSignLen bytes from the reader and requires them to equal the PNG file signature (\\x89PNG\\r\\n\\x1a\\n). If the prefix does not match, the input is not a PNG image, so it refuses to continue and returns this error. This guards io.Copy downstream from treating non-PNG data as an image.","triggerScenarios":"Calling transfer (via main) with a reader whose first bytes are not the 8-byte PNG signature — e.g. a JPEG/GIF file, an HTML error page, an empty body, or a text file.","commonSituations":"Downloading an image URL that returned a 404 HTML page instead of a PNG; piping the wrong local file; a server content-type mismatch where the extension says .png but the payload is another format.","solutions":["Verify the input source is actually a PNG (open it locally or check magic bytes before calling).","Check the URL/endpoint returned 200 with image/png content, not an error page.","If other formats should be accepted, remove or broaden the signature check in transfer.","Handle the error at the caller and surface a clear 'input is not a PNG' message to the user."],"exampleFix":"// before\nif !bytes.HasPrefix(memory.Bytes(), []byte(pngSign)) {\n    return n, errors.New(\"not png\")\n}\n// after\nif !bytes.HasPrefix(memory.Bytes(), []byte(pngSign)) {\n    return n, fmt.Errorf(\"not png: got header %q\", memory.Bytes()[:n])\n}","handlingStrategy":"validation","validationCode":"func looksLikePNG(r io.Reader) (bool, error) {\n    header := make([]byte, 8)\n    if _, err := io.ReadFull(r, header); err != nil {\n        return false, err\n    }\n    return bytes.Equal(header, []byte(\"\\x89PNG\\r\\n\\x1a\\n\")), nil\n}","typeGuard":"func isPNGHeader(b []byte) bool {\n    return len(b) >= 8 && bytes.Equal(b[:8], []byte(\"\\x89PNG\\r\\n\\x1a\\n\"))\n}","tryCatchPattern":"if n, err := transfer(w, r); err != nil {\n    if err.Error() == \"not png\" {\n        http.Error(w, \"input is not a PNG image\", http.StatusUnsupportedMediaType)\n        return\n    }\n    return n, err\n}","preventionTips":["Check Content-Type is image/png before feeding a download to transfer","Sniff the first 8 magic bytes yourself before calling","Do not trust file extensions; a .png URL may return an error page","Use golang.org/x/image or http.DetectContentType to pre-validate"],"tags":["io","validation","png","file-format"],"backgroundTag":"invalid-file-signature","analyzedSha":"3c475a78e54336c6255e925ff66b8ef4da6a2ae7","analyzedAt":"2026-09-02T10:14:38.492Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}