diff --git a/src/apk_defines.h b/src/apk_defines.h
index 8470835dc16fc599c55abcd55935482a3faff38c..f1b0f8d64a5e086e27686b5875ee847f8d55d1b7 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -60,7 +60,8 @@ enum {
 	APKE_PACKAGE_NOT_FOUND,
 	APKE_INDEX_STALE,
 	APKE_FILE_INTEGRITY,
-	APKE_UVOL
+	APKE_CACHE_NOT_AVAILABLE,
+	APKE_UVOL,
 };
 
 static inline void *ERR_PTR(long error) { return (void*) error; }
diff --git a/src/database.c b/src/database.c
index b009f74816e5494e79968e2537bd5524e92250a4..10e9776bd73ab164e4c01ab57e047f36a82973bd 100644
--- a/src/database.c
+++ b/src/database.c
@@ -1647,7 +1647,10 @@ int apk_db_open(struct apk_database *db, struct apk_ctx *ac)
 			mkdirat(db->root_fd, "var/cache", 0755);
 			mkdirat(db->root_fd, "var/cache/apk", 0755);
 			db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC);
-			if (db->cache_fd < 0) goto ret_errno;
+			if (db->cache_fd < 0) {
+				if (ac->open_flags & APK_OPENF_WRITE) goto ret_errno;
+				db->cache_fd = -APKE_CACHE_NOT_AVAILABLE;
+			}
 		}
 	}
 
@@ -1814,8 +1817,8 @@ void apk_db_close(struct apk_database *db)
 		db->cache_remount_dir = NULL;
 	}
 
-	if (db->cache_fd) close(db->cache_fd);
-	if (db->lock_fd) close(db->lock_fd);
+	if (db->cache_fd > 0) close(db->cache_fd);
+	if (db->lock_fd > 0) close(db->lock_fd);
 }
 
 int apk_db_get_tag_id(struct apk_database *db, apk_blob_t tag)
diff --git a/src/io.c b/src/io.c
index 6628c362421ca9d6638a58b9b0b9920f479bbfa2..9acf1e64e9d5a2cb9c818b0f81bbf08b579ecc02 100644
--- a/src/io.c
+++ b/src/io.c
@@ -33,6 +33,11 @@
 
 size_t apk_io_bufsize = 128*1024;
 
+static inline int atfd_error(int atfd)
+{
+	return atfd < -1 && atfd != AT_FDCWD;
+}
+
 ssize_t apk_write_fully(int fd, const void *ptr, size_t size)
 {
 	ssize_t i = 0, r;
@@ -528,6 +533,8 @@ struct apk_istream *__apk_istream_from_file(int atfd, const char *file, int try_
 {
 	int fd;
 
+	if (atfd_error(atfd)) return ERR_PTR(atfd);
+
 	fd = openat(atfd, file, O_RDONLY | O_CLOEXEC);
 	if (fd < 0) return ERR_PTR(-errno);
 
@@ -588,6 +595,8 @@ apk_blob_t apk_blob_from_file(int atfd, const char *file)
 	struct stat st;
 	char *buf;
 
+	if (atfd_error(atfd)) return APK_BLOB_NULL;
+
 	fd = openat(atfd, file, O_RDONLY | O_CLOEXEC);
 	if (fd < 0)
 		return APK_BLOB_NULL;
@@ -615,6 +624,8 @@ int apk_blob_to_file(int atfd, const char *file, apk_blob_t b, unsigned int flag
 {
 	int fd, r, len;
 
+	if (atfd_error(atfd)) return atfd;
+
 	fd = openat(atfd, file, O_CREAT | O_WRONLY | O_CLOEXEC, 0644);
 	if (fd < 0)
 		return -errno;
@@ -685,6 +696,8 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags,
 	unsigned int xattr_hash_alg = (flags >> 8) & 0xff;
 	int atflags = 0;
 
+	if (atfd_error(atfd)) return atfd;
+
 	memset(fi, 0, sizeof *fi);
 	if (flags & APK_FI_NOFOLLOW)
 		atflags |= AT_SYMLINK_NOFOLLOW;
@@ -918,6 +931,8 @@ struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode)
 	struct apk_ostream *os;
 	int fd;
 
+	if (atfd_error(atfd)) return ERR_PTR(atfd);
+
 	if (snprintf(tmpname, sizeof tmpname, "%s.tmp", file) >= sizeof tmpname)
 		return ERR_PTR(-ENAMETOOLONG);
 
diff --git a/src/print.c b/src/print.c
index 558527e7c5ed6580f799aba3452ed14c3123d74b..124899557569cb5be876feea7dc1bf2e16999d63 100644
--- a/src/print.c
+++ b/src/print.c
@@ -56,6 +56,7 @@ const char *apk_error_str(int error)
 	case APKE_PACKAGE_NOT_FOUND:		return "could not find a repo which provides this package (check repositories file and run 'apk update')";
 	case APKE_INDEX_STALE:			return "package mentioned in index not found (try 'apk update')";
 	case APKE_FILE_INTEGRITY:		return "file integrity error";
+	case APKE_CACHE_NOT_AVAILABLE:		return "cache not available";
 	case APKE_UVOL:				return "uvol error";
 	default:
 		return strerror(error);