{
  "schema_version": 2,
  "id": "develop/clients/hiredis/handle-replies",
  "title": "Handle command replies",
  "url": "https://redis.io/docs/latest/develop/clients/hiredis/handle-replies/",
  "summary": "Handle command replies with `hiredis`.",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-09-09T11:06:49+01:00",
  "page_type": "content",
  "content_hash": "608bbe726f3074b28f7d8c194774d537b8e0ec3cfee3623ec6c97bc9b159159c",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "The `redisCommand()` and `redisCommandArgv()` functions return\na pointer to a `redisReply` object when you issue a command (see\n[Issue commands](https://redis.io/docs/latest/develop/clients/hiredis/issue-commands)\nfor more information). This type supports all\nreply formats defined in the\n[RESP2 and RESP3](https://redis.io/docs/latest/develop/reference/protocol-spec#resp-protocol-description)\nprotocols, so its content varies greatly between calls.\n\nA simple example is the status response returned by the [`SET`](https://redis.io/docs/latest/commands/set)\ncommand. The code below shows how to get this from the `redisReply`\nobject:\n\n[code example]\n\nA null reply indicates an error, so you should always check for this.\nIf an error does occur, then the `redisContext` object will have a\nnon-zero error number in its integer `err` field and a textual\ndescription of the error in its `errstr` field.\n\nFor `SET`, a successful call will simply return an \"OK\" string that you\ncan access with the `reply->str` field. The code in the example prints\nthis to the console, but you should check for the specific value to ensure\nthe command executed correctly.\n\nThe `redisCommand()` call allocates memory for the reply, so you should\nalways free it using `freeReplyObject()` when you have finished using\nthe reply. If you want to reuse the reply variable then it is wise to\nset it to `NULL` after you free it, so that you don't accidentally use\nthe stale pointer later."
    },
    {
      "id": "reply-formats",
      "title": "Reply formats",
      "role": "content",
      "text": "The Redis\n[`RESP`](https://redis.io/docs/latest/develop/reference/protocol-spec#resp-protocol-description)\nprotocols support several different reply formats for commands.\n\nYou can find the reply format for a command at the end of its\nreference page in the RESP2/RESP3 Reply section (for example, the\n[`INCRBY`](https://redis.io/docs/latest/commands/incrby) page shows that the\ncommand has an integer result). You can also determine the format\nusing the `type` field of the reply object. This contains a\ndifferent integer value for each type. The `hiredis.h` header file\ndefines constants for all of these integer values (for example `REDIS_REPLY_STRING`).\n\nThe `redisReply` struct has several fields to contain different\ntypes of replies, with different fields being set depending on\nthe value of the `type` field. The table below shows the type\nconstants, the corresponding reply type, and the fields you can\nuse to access the reply value:\n\n| Constant | Type | Relevant fields of `redisReply` | RESP protocol |\n| :- | :- |:- | :- |\n| `REDIS_REPLY_STATUS` | [Simple string](https://redis.io/docs/latest/develop/reference/protocol-spec#simple-strings) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |\n| `REDIS_REPLY_ERROR` | [Simple error](https://redis.io/docs/latest/develop/reference/protocol-spec#simple-errors) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |\n| `REDIS_REPLY_INTEGER` | [Integer](https://redis.io/docs/latest/develop/reference/protocol-spec#integers) | `reply->integer`: the integer value (`long long`)| 2, 3 |\n| `REDIS_REPLY_NIL` | [Null](https://redis.io/docs/latest/develop/reference/protocol-spec#nulls) | No data | 2, 3 |\n| `REDIS_REPLY_STRING` | [Bulk string](https://redis.io/docs/latest/develop/reference/protocol-spec#bulk-strings) |`reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |\n| `REDIS_REPLY_ARRAY` | [Array](https://redis.io/docs/latest/develop/reference/protocol-spec#arrays) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 2, 3 |\n| `REDIS_REPLY_DOUBLE` | [Double](https://redis.io/docs/latest/develop/reference/protocol-spec#doubles) | `reply->str`: double value as string (`char*`)<br/> `reply->len`: the string length (`size_t`) | 3 |\n| `REDIS_REPLY_BOOL` | [Boolean](https://redis.io/docs/latest/develop/reference/protocol-spec#booleans) | `reply->integer`: the boolean value, 0 or 1 (`long long`) | 3 |\n| `REDIS_REPLY_MAP` | [Map](https://redis.io/docs/latest/develop/reference/protocol-spec#maps) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |\n| `REDIS_REPLY_SET` | [Set](https://redis.io/docs/latest/develop/reference/protocol-spec#sets) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |\n| `REDIS_REPLY_PUSH` | [Push](https://redis.io/docs/latest/develop/reference/protocol-spec#pushes) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |\n| `REDIS_REPLY_BIGNUM` | [Big number](https://redis.io/docs/latest/develop/reference/protocol-spec#big-numbers) | `reply->str`: number value as string (`char*`)<br/> `reply->len`: the string length (`size_t`) | 3 |\n| `REDIS_REPLY_VERB` | [Verbatim string](https://redis.io/docs/latest/develop/reference/protocol-spec#verbatim-strings) |`reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`)<br/> `reply->vtype`: content type (`char[3]`) | 3 |"
    },
    {
      "id": "reply-format-processing-examples",
      "title": "Reply format processing examples",
      "role": "content",
      "text": "The sections below explain how to process specific reply types in\nmore detail."
    },
    {
      "id": "integers",
      "title": "Integers",
      "role": "content",
      "text": "The `REDIS_REPLY_INTEGER` and `REDIS_REPLY_BOOL` reply types both\ncontain values in `reply->integer`. However, `REDIS_REPLY_BOOL` is\nrarely used. Even when the command essentially returns a boolean value,\nthe reply is usually reported as an integer. \n\n[code example]"
    },
    {
      "id": "strings",
      "title": "Strings",
      "role": "content",
      "text": "The `REDIS_REPLY_STATUS`, `REDIS_REPLY_ERROR`, `REDIS_REPLY_STRING`,\n`REDIS_REPLY_DOUBLE`, `REDIS_REPLY_BIGNUM`, and `REDIS_REPLY_VERB`\nare all returned as strings, with the main difference lying in how\nyou interpret them. For all these types, the string value is\nreturned in `reply->str` and the length of the string is in\n`reply->len`. The example below shows some of the possibilities.\n\n[code example]"
    },
    {
      "id": "arrays-and-maps",
      "title": "Arrays and maps",
      "role": "content",
      "text": "Arrays (reply type `REDIS_REPLY_ARRAY`) and maps (reply type `REDIS_REPLY_MAP`)\nare returned by commands that retrieve several values at the\nsame time. For both types, the number of elements in the reply is contained in\n`reply->elements` and the pointer to the array itself is `reply->element`.\nEach item in the array is of type `redisReply`. The array elements\nare typically simple types rather than arrays or maps.\n\nThe example below shows how to get the items from a\n[list](https://redis.io/docs/latest/develop/data-types/lists):\n\n[code example]\n\nA map is essentially the same as an array but it has the extra\nguarantee that the items will be listed in key-value pairs.\nThe example below shows how to get all the fields from a\n[hash](https://redis.io/docs/latest/develop/data-types/hashes) using\n[`HGETALL`](https://redis.io/docs/latest/commands/hgetall):\n\n[code example]"
    },
    {
      "id": "handling-errors",
      "title": "Handling errors",
      "role": "content",
      "text": "When a command executes successfully, the `err` field of the context\nobject will be set to zero. If a command fails, it will return either\n`NULL` or `REDIS_ERR`, depending on which function and command you used. When\nthis happens, `context->err` will contain an error code\n\n-   `REDIS_ERR_IO`: There was an I/O error while creating the connection,\n    or while trying to write or read data. Whenever `context->err` contains\n    `REDIS_ERR_IO`, you can use the features of the standard library file\n    [`errno.h`](https://en.wikipedia.org/wiki/Errno.h) to find out more\n    information about the error.\n-   `REDIS_ERR_EOF`: The server closed the connection which resulted in an empty read.\n-   `REDIS_ERR_PROTOCOL`: There was an error while parsing the\n    [RESP protocol](https://redis.io/docs/latest/develop/reference/protocol-spec).\n-   `REDIS_ERR_OTHER`: Any other error. Currently, it is only used when the connection\n    hostname can't be resolved.\n\nThe context object also has an `errstr` field that contains a descriptive error message."
    }
  ],
  "examples": [
    {
      "id": "overview-ex0",
      "language": "c",
      "code": "redisReply *reply = redisCommand(c, \"SET greeting Hello\");\n\n// Check and free the reply.\nif (reply != NULL) {\n    printf(\"Reply: %s\\n\", reply->str);\n    freeReplyObject(reply);\n    reply = NULL;\n}",
      "section_id": "overview"
    },
    {
      "id": "integers-ex0",
      "language": "c",
      "code": "// Add some values to a set.\nredisReply *reply = redisCommand(c, \"SADD items bread milk peas\");\n\nif (reply->type == REDIS_REPLY_INTEGER) {\n    // Report status.\n    printf(\"Integer reply\\n\");\n    printf(\"Number added: %lld\\n\", reply->integer);\n    // >>> Number added: 3\n}\n\nfreeReplyObject(reply);\nreply = NULL;\n\n\nreply = redisCommand(c, \"SISMEMBER items bread\");\n\n// This also gives an integer reply but you should interpret\n// it as a boolean value.\nif (reply->type == REDIS_REPLY_INTEGER) {\n    // Respond to boolean integer value.\n    printf(\"Integer reply\\n\");\n    \n    if (reply->integer == 0) {\n        printf(\"Items set has no member 'bread'\\n\");\n    } else {\n        printf(\"'Bread' is a member of items set\\n\");\n    }\n    // >>> 'Bread' is a member of items set\n}\n\nfreeReplyObject(reply);\nreply = NULL;",
      "section_id": "integers"
    },
    {
      "id": "strings-ex0",
      "language": "c",
      "code": "// Set a numeric value in a string.\nreply = redisCommand(c, \"SET number 1.5\");\n\n// This gives a status reply.\nif (reply->type == REDIS_REPLY_STATUS) {\n    // Report status.\n    printf(\"Status reply\\n\");\n    printf(\"Reply: %s\\n\", reply->str); // >>> Reply: OK\n}\n\nfreeReplyObject(reply);\nreply = NULL;\n\n\n// Attempt to interpret the key as a hash.\nreply = redisCommand(c, \"HGET number field1\");\n\n// This gives an error reply.\nif (reply->type == REDIS_REPLY_ERROR) {\n    // Report the error.\n    printf(\"Error reply\\n\");\n    printf(\"Reply: %s\\n\", reply->str);\n    // >>> Reply: WRONGTYPE Operation against a key holding the wrong kind of value\n}\n\nfreeReplyObject(reply);\nreply = NULL;\n\n\nreply = redisCommand(c, \"GET number\");\n\n// This gives a simple string reply.\nif (reply->type == REDIS_REPLY_STRING) {\n    // Display the string.\n    printf(\"Simple string reply\\n\");\n    printf(\"Reply: %s\\n\", reply->str); // >>> Reply: 1.5\n}\n\nfreeReplyObject(reply);\nreply = NULL;\n\n\nreply = redisCommand(c, \"ZADD prices 1.75 bread 5.99 beer\");\n\n// This gives an integer reply.\nif (reply->type == REDIS_REPLY_INTEGER) {\n    // Display the integer.\n    printf(\"Integer reply\\n\");\n    printf(\"Number added: %lld\\n\", reply->integer);\n    // >>> Number added: 2\n}\n\nfreeReplyObject(reply);\nreply = NULL;\n\n\nreply = redisCommand(c, \"ZSCORE prices bread\");\n\n// This gives a string reply with RESP2 and a double reply\n// with RESP3, but you handle it the same way in either case.\nif (reply->type == REDIS_REPLY_STRING) {\n    printf(\"String reply\\n\");\n    \n    char *endptr; // Not used.\n    double price = strtod(reply->str, &endptr);\n    double discounted = price * 0.75;\n    printf(\"Discounted price: %.2f\\n\", discounted);\n    // >>> Discounted price: 1.31\n}\n\nfreeReplyObject(reply);\nreply = NULL;",
      "section_id": "strings"
    },
    {
      "id": "arrays-and-maps-ex0",
      "language": "c",
      "code": "reply = redisCommand(c, \"RPUSH things thing0 thing1 thing2 thing3\");\n\nprintf(\"Added %lld items\\n\", reply->integer);\n// >>> Added 4 items\nfreeReplyObject(reply);\nreply = NULL;\n\n\nreply = redisCommand(c, \"LRANGE things 0 -1\");\n\nfor (int i = 0; i < reply->elements; ++i) {\n    if (reply->element[i]->type == REDIS_REPLY_STRING) {\n        printf(\"List item %d: %s\\n\", i, reply->element[i]->str);\n    }\n}\n// >>> List item 0: thing0\n// >>> List item 1: thing1\n// >>> List item 2: thing2\n// >>> List item 3: thing3",
      "section_id": "arrays-and-maps"
    },
    {
      "id": "arrays-and-maps-ex1",
      "language": "c",
      "code": "const char *hashCommand[] = {\n    \"HSET\", \"details\",\n    \"name\", \"Mr Benn\",\n    \"address\", \"52 Festive Road\",\n    \"hobbies\", \"Cosplay\"\n};\n\nreply = redisCommandArgv(c, 8, hashCommand, NULL);\n\nprintf(\"Added %lld fields\\n\", reply->integer);\n// >>> Added 3 fields\n\nfreeReplyObject(reply);\nreply = NULL;\n\n\nreply = redisCommand(c, \"HGETALL details\");\n\n// This gives an array reply with RESP2 and a map reply with\n// RESP3, but you handle it the same way in either case.\nif (reply->type == REDIS_REPLY_ARRAY) {        \n    for (int i = 0; i < reply->elements; i += 2) {\n        char *key = reply->element[i]->str;\n        char *value = reply->element[i + 1]->str;\n        printf(\"Key: %s, value: %s\\n\", key, value);\n    }\n    // >>> Key: name, value: Mr Benn\n    // >>> Key: address, value: 52 Festive Road\n    // >>> Key: hobbies, value: Cosplay\n}",
      "section_id": "arrays-and-maps"
    }
  ]
}
