os.getxattr
Linux only - these functions and constants do not exist on Windows or macOS. Names carry a namespace prefix (unprivileged code uses 'user.'), values are bytes up to XATTR_SIZE_MAX (64 KiB on Linux), and the filesystem must support them.
Common call
os.setxattr(path, 'user.tag', b'blue')
Returns
os.getxattr(path, 'user.tag') → b'blue'
Replaces
getfattr / setfattr command-line calls
Watch out
Values must be bytes; names need a namespace like 'user.'
os.getxattr(pathpath — The file (or an open file descriptor). listxattr: None examines the current directory.type: str | bytes | PathLike | int · required, attributeattribute — Attribute name including its namespace, e.g. 'user.tag'. str is encoded with the filesystem encoding.type: str | bytes | PathLike · required, *, follow_symlinksfollow_symlinks — False reads/writes the attributes of a symlink itself.type: bool · default: True=True)
→ bytes | list[str] | None
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | str | bytes | PathLike | int | yes | The file (or an open file descriptor). listxattr: None examines the current directory. |
| attribute | str | bytes | PathLike | yes | Attribute name including its namespace, e.g. 'user.tag'. str is encoded with the filesystem encoding. |
| value | bytes-like | yes | setxattr: the new value; a str raises TypeError. |
| flags | int | no (0) | setxattr: 0 (create or replace), XATTR_CREATE (must not exist yet) or XATTR_REPLACE (must already exist). |
| follow_symlinks | bool | no (True) | False reads/writes the attributes of a symlink itself. |
Return value
bytes | list[str] | None — getxattr returns the value as bytes, listxattr a list of attribute names as str; setxattr and removexattr return None.
Common patterns
Tag a file (Linux)
Store, read back, list and remove a user attribute.
import os os.setxattr('photo.jpg', 'user.rating', b'5') os.getxattr('photo.jpg', 'user.rating') # b'5' os.listxattr('photo.jpg') # ['user.rating'] os.removexattr('photo.jpg', 'user.rating')
Create only if absent
XATTR_CREATE raises FileExistsError instead of overwriting.
import os try: os.setxattr(path, 'user.origin', b'import', os.XATTR_CREATE) except FileExistsError: pass
Optional metadata, portable
Fall back cleanly where xattrs do not exist, are not supported, or are absent.
import os def get_tag(path): if not hasattr(os, 'getxattr'): return None try: return os.getxattr(path, 'user.tag').decode() except OSError: return None
Examples
1. A guarded reader works everywhere
import os
def get_tag(path):
if not hasattr(os, 'getxattr'):
return None
try:
return os.getxattr(path, 'user.tag')
except OSError:
return None
open('f.txt', 'w').close()
get_tag('f.txt') is None
Returns
True2. Names have a namespace
'user.comment'.partition('.')
Returns
('user', '.', 'comment')3. str names become bytes
import os
os.fsencode('user.tag')
Returns
b'user.tag'4. Values are bytes
import json
value = json.dumps({'rating': 5}).encode()
(value, len(value) <= 65536)
Returns
(b'{"rating": 5}', True)5. What XATTR_CREATE raises
import errno
type(OSError(errno.EEXIST, 'File exists')).__name__
Returns
'FileExistsError'Pitfalls
1. Forgetting the namespace
A bare name such as 'tag' is rejected by Linux (OSError, errno EOPNOTSUPP). Ordinary users can only write the 'user.' namespace.
'tag'
name = 'tag' name.split('.', 1)[0] in ('user', 'trusted', 'security', 'system')
False
'user.tag'
name = 'user.tag' name.split('.', 1)[0] in ('user', 'trusted', 'security', 'system')
True
2. Storing a value larger than the limit
On Linux a value over XATTR_SIZE_MAX (65536 bytes) fails with OSError (errno E2BIG). Check the size, or store a reference instead.
70000 bytes
value = b'x' * 70000 len(value) <= 65536
False
small value
import hashlib value = hashlib.sha256(b'x' * 70000).hexdigest().encode() len(value) <= 65536
True
When to use
Use it
- Small per-file metadata on Linux: tags, checksums, origin markers
- Reading security labels and ACL data (the security.* and system.* namespaces)
Reach for something else
- Portable metadata → a sidecar file or a database
- Data that must survive copies to other filesystems, zip files or cloud storage - attributes are often dropped
- macOS extended attributes → not exposed by os (third-party packages)
Notes
CPython impl
getxattr/lgetxattr/fgetxattr and the matching set/list/remove calls in Modules/posixmodule.c, chosen by follow_symlinks and whether path is an fd
Availability
Linux only (the docs: "These functions are all available on Linux only"), added in 3.3. None of these names exist on Windows (verified)
Values
XATTR_CREATE = 1, XATTR_REPLACE = 2, XATTR_SIZE_MAX = 65536 (CPython 3.12 on Linux)
Errors (Linux)
getxattr of a missing name and setxattr with XATTR_REPLACE on a missing name: OSError errno 61 (ENODATA). XATTR_CREATE on an existing name: FileExistsError. Name without namespace: OSError errno 95. Value over 64 KiB: OSError errno 7 (verified on an ext4-type filesystem)
FAQ
The extended-attribute functions are Linux only - Windows and macOS builds of Python do not define them. The examples therefore show the naming and value rules and a hasattr-guarded reader instead of calling them.