{"record":{"id":"0f7c3c70558eee23","repo":"JuliusBrussee/caveman","slug":"objectstore-get-q-w","errorCode":null,"errorMessage":"objectstore: get %q: %w","messagePattern":"objectstore: get %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/objectstore/objectstore.go","lineNumber":286,"sourceCode":"\treturn nil\n}\n\nfunc (m *minioStore) Put(ctx context.Context, key string, body []byte, contentType string) error {\n\tif contentType == \"\" {\n\t\tcontentType = \"application/octet-stream\"\n\t}\n\t_, err := m.client.PutObject(ctx, m.bucket, key, bytes.NewReader(body), int64(len(body)),\n\t\tminio.PutObjectOptions{ContentType: contentType})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"objectstore: put %q: %w\", key, err)\n\t}\n\treturn nil\n}\n\nfunc (m *minioStore) Get(ctx context.Context, key string) ([]byte, error) {\n\tobj, err := m.client.GetObject(ctx, m.bucket, key, minio.GetObjectOptions{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"objectstore: get %q: %w\", key, err)\n\t}\n\tdefer obj.Close()\n\tmaxBytes := int64(env.Int(\"CAVE_OBJECTSTORE_MAX_READ_BYTES\", 64<<20))\n\tif maxBytes <= 0 {\n\t\tmaxBytes = 64 << 20\n\t}\n\tbody, err := io.ReadAll(io.LimitReader(obj, maxBytes+1))\n\tif err != nil {\n\t\tif minio.ToErrorResponse(err).Code == \"NoSuchKey\" {\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\t\treturn nil, fmt.Errorf(\"objectstore: read %q: %w\", key, err)\n\t}\n\tif int64(len(body)) > maxBytes {\n\t\treturn nil, ErrTooLarge\n\t}\n\treturn body, nil\n}","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/objectstore/objectstore.go#L268-L304","documentation":"minioStore.Get wraps MinIO GetObject errors with 'objectstore: get %q: %w', naming the missing or unreadable key. It throws when the object stat/fetch fails — most commonly because the key does not exist — as well as for auth, network, and permission failures.","triggerScenarios":"Calling Store.Get for a key that was never written or was deleted/purged (Probe cleanup, version expiry), or when the GetObject call fails on network/auth/permission; the error is wrapped before reading the body.","commonSituations":"Reading an object after its TTL/purge cycle; key constructed with a different prefix or encoding than the writer used; credentials lacking s3:GetObject; MinIO endpoint unreachable after restart.","solutions":["Check the wrapped code: treat NoSuchKey as an expected miss and return a not-found result instead of a 500.","Verify the exact key (prefix, encoding, trailing slashes) matches what Put wrote; log both sides.","Confirm credentials/IAM allow GetObject on the bucket.","Check connectivity to the endpoint and retry transient network errors with backoff."],"exampleFix":"// before\nbody, err := store.Get(ctx, key)\nif err != nil { return err } // 500 on every missing object\n// after\nbody, err := store.Get(ctx, key)\nif err != nil {\n    var resp minio.ErrorResponse\n    if errors.As(err, &resp) && resp.Code == \"NoSuchKey\" {\n        return nil, ErrObjectNotFound\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"body, err := store.Get(ctx, key)\nif err != nil {\n    var resp minio.ErrorResponse\n    if errors.As(err, &resp) && resp.Code == \"NoSuchKey\" {\n        return nil, ErrObjectNotFound // expected miss, not a 500\n    }\n    return fmt.Errorf(\"get failed: %w\", err) // retryable for transient codes\n}","preventionTips":["Map NoSuchKey to a domain not-found error instead of a generic failure.","Keep key construction (prefix/encoding) in one shared helper used by Put and Get.","Grant GetObject in IAM alongside Put/Delete.","Retry only transient errors; do not retry NoSuchKey."],"tags":["minio","s3","download","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}