{"record":{"id":"da89c5a5ec9c9d6c","repo":"TheAlgorithms/Python","slug":"ciphertext-must-be-a-string","errorCode":null,"errorMessage":"ciphertext must be a string","messagePattern":"ciphertext must be a string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ciphers/autokey.py","lineNumber":104,"sourceCode":"    >>> decrypt(\"vvjfpk wj ohvp su ddylsv\", \"\")\n    Traceback (most recent call last):\n        ...\n    ValueError: key is empty\n    >>> decrypt(527.26, \"TheAlgorithms\")\n    Traceback (most recent call last):\n        ...\n    TypeError: ciphertext must be a string\n    >>> decrypt(\"\", \"TheAlgorithms\")\n    Traceback (most recent call last):\n        ...\n    ValueError: ciphertext is empty\n    >>> decrypt(\"vvjfpk wj ohvp su ddylsv\", 2)\n    Traceback (most recent call last):\n        ...\n    TypeError: key must be a string\n    \"\"\"\n    if not isinstance(ciphertext, str):\n        raise TypeError(\"ciphertext must be a string\")\n    if not isinstance(key, str):\n        raise TypeError(\"key must be a string\")\n\n    if not ciphertext:\n        raise ValueError(\"ciphertext is empty\")\n    if not key:\n        raise ValueError(\"key is empty\")\n\n    key = key.lower()\n    ciphertext_iterator = 0\n    key_iterator = 0\n    plaintext = \"\"\n    while ciphertext_iterator < len(ciphertext):\n        if (\n            ord(ciphertext[ciphertext_iterator]) < 97\n            or ord(ciphertext[ciphertext_iterator]) > 122\n        ):\n            plaintext += ciphertext[ciphertext_iterator]","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/ciphers/autokey.py#L86-L122","documentation":"Raised by autokey decrypt() when the ciphertext argument is not a str. decrypt() mirrors encrypt()'s validation: it walks the ciphertext character-by-character with ord() range checks (97-122) and appends recovered characters to the key stream, so it demands a string.","triggerScenarios":"Calling decrypt(527.26, 'TheAlgorithms'), decrypt(None, key), decrypt(b'...', key) (bytes are not str), or any non-str first argument.","commonSituations":"Round-tripping data that was serialized to bytes after encryption, or passing an int because encrypt() was called with swapped arguments earlier.","solutions":["Pass the exact str that encrypt() returned: decrypt(encrypt(p, k), k).","Decode bytes: ciphertext.decode('utf-8') before decrypting.","Verify argument order: decrypt(ciphertext, key)."],"exampleFix":"# before\ndecrypt(b'vvjfpk wj ohvp su ddylsv', 'TheAlgorithms')  # bytes -> TypeError\n\n# after\ndecrypt('vvjfpk wj ohvp su ddylsv', 'TheAlgorithms')","handlingStrategy":"type-guard","validationCode":"if isinstance(ciphertext, bytes):\n    ciphertext = ciphertext.decode('utf-8')\nassert isinstance(ciphertext, str)","typeGuard":"def is_str(v: object) -> bool:\n    return isinstance(v, str)","tryCatchPattern":"try:\n    decrypt(c, k)\nexcept TypeError:\n    c = c.decode() if isinstance(c, bytes) else str(c)\n    plaintext = decrypt(c, k)","preventionTips":["Round-trip with the exact str encrypt() returned; avoid re-serializing to bytes.","Keep argument order decrypt(ciphertext, key) straight."],"tags":["cipher","type-error","python"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}