{"record":{"id":"f4816a7c098d545c","repo":"Hmbown/CodeWhale","slug":"nsposixerrordomain","errorCode":"NSPOSIXErrorDomain","errorMessage":"NSPOSIXErrorDomain errno (no message text)","messagePattern":"NSPOSIXErrorDomain errno \\(no message text\\)","errorType":"error_code","errorClass":"NSError","httpStatus":null,"severity":"error","filePath":"pet/swift/PetHabitatStore.swift","lineNumber":120,"sourceCode":"        guard file >= 0 else { throw Self.ioError() }\n        defer { close(file) }\n        let info = try Self.regular(file)\n        guard info.st_size >= 0 && info.st_size <= limit else { throw Self.invalid(\"The saved habitat exceeds 8 MiB.\") }\n        var value = Data(), buffer = [UInt8](repeating: 0, count: 16_384)\n        while true {\n            let count = Darwin.read(file, &buffer, min(buffer.count, limit + 1 - value.count))\n            if count < 0 && errno == EINTR { continue }\n            guard count >= 0 else { throw Self.ioError() }\n            if count == 0 { break }\n            value.append(contentsOf: buffer.prefix(count))\n            guard value.count <= limit else { throw Self.invalid(\"The saved habitat exceeds its size limit.\") }\n        }\n        return value\n    }\n\n    private static func regular(_ file: Int32) throws -> stat {\n        var info = stat()\n        guard fstat(file, &info) == 0 else { throw ioError() }\n        guard info.st_mode & S_IFMT == S_IFREG, info.st_nlink == 1 else { throw invalid(\"A habitat file must be a regular file without links.\") }\n        return info\n    }\n    private static func ioError() -> Error { NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) }\n    private static func invalid(_ message: String) -> Error { NSError(domain: \"CodewhalePet\", code: 1, userInfo: [NSLocalizedDescriptionKey: message]) }\n}\n","sourceCodeStart":102,"sourceCodeEnd":127,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/swift/PetHabitatStore.swift#L102-L127","documentation":"PetHabitatStore throws an NSError in NSPOSIXErrorDomain whose code is the raw errno when a Darwin system call fails. In this store it originates from ioError(), thrown after failures of fstat, open/openat, write, fsync, linkat/renameat, or flock during load/save. It carries no message text, so the POSIX errno code itself (e.g. ENOENT, EACCES, EINTR-handled elsewhere, ENOSPC, EAGAIN) is the only diagnostic.","triggerScenarios":"fstat on a lock or data file fails in regular(); open/openat with O_NOFOLLOW fails because the target is a symlink (ELOOP) or missing and errno != ENOENT; write returns <= 0 other than EINTR (e.g. ENOSPC, EIO); fsync fails; flock(LOCK_EX|LOCK_NB) returns EWOULDBLOCK because another process holds the lock; renameat/linkat fail; or the lock file cannot be reopened inside coordinated().","commonSituations":"Disk full when saving habitat data; two app processes contending for the non-blocking exclusive lock; the store directory or lock file replaced by a symlink or a hard-linked file; permission changes on the 0o700 directory; file system errors on external/network volumes where fsync or rename fails.","solutions":["Log the NSError code and map it with strerror(code) to identify the actual POSIX errno before changing code.","If the code is EWOULDBLOCK/EAGAIN, another process holds the flock: retry after the other writer finishes instead of treating it as corruption.","If the code is ENOSPC, free disk space (or reduce store usage) and retry save.","If the code is EACCES or EPERM, repair permissions on the store directory (expected 0o700) and lock/data files, and ensure the process user owns them.","If the code is ELOOP, remove any symlink or hard link that replaced the habitat JSON or lock file and let the store recreate them.","If the code is EIO or persistent, check disk health / move the store to a local volume (fsync and O_NOFOLLOW semantics can fail on network mounts)."],"exampleFix":"// before\ndo { try store.save(data) } catch { print(\"save failed\") }\n// after\ndo {\n    try store.save(data)\n} catch let error as NSError where error.domain == NSPOSIXErrorDomain {\n    print(\"POSIX failure: \\(String(cString: strerror(Int32(error.code)))) (errno \\(error.code))\")\n    if error.code == Int32(EWOULDBLOCK) { /* another writer holds the lock; retry later */ }\n}","handlingStrategy":"try-catch","validationCode":"import Darwin\nfunc preflightStore(_ url: URL) -> String? {\n    let fm = FileManager.default\n    guard fm.fileExists(atPath: url.path) else { return nil }\n    guard (try? fm.attributesOfItem(atPath: url.path))[.type] as? FileAttributeType == .typeRegular else {\n        return \"Store path is not a regular file/symlink present\"\n    }\n    guard fm.isWritableFile(atPath: url.path) else { return \"No write permission on store directory\" }\n    return nil\n}","typeGuard":"func isPosixStoreError(_ error: Error) -> Bool {\n    (error as NSError).domain == NSPOSIXErrorDomain\n}\nfunc errno(of error: Error) -> Int32 {\n    Int32((error as NSError).code)\n}","tryCatchPattern":"do {\n    try store.save(data)\n} catch let e as NSError where e.domain == NSPOSIXErrorDomain {\n    switch Int32(e.code) {\n    case EWOULDBLOCK, EAGAIN: scheduleRetry()\n    case ENOSPC: freeDiskSpaceThenRetry()\n    case EACCES, EPERM: promptUserToFixPermissions()\n    default: reportFatal(String(cString: strerror(Int32(e.code))))\n    }\n} catch {\n    reportFatal(error.localizedDescription)\n}","preventionTips":["Catch NSPOSIXErrorDomain specifically and decode errno with strerror() instead of relying on the empty message text.","Handle EWOULDBLOCK from the non-blocking flock with backoff/retry, since concurrent writers are an expected condition.","Keep the store on a local, writable volume and verify the directory keeps its 0o700 permissions.","Never symlink or hard-link the habitat JSON, segment archives, or lock files — O_NOFOLLOW and nlink==1 checks will fail the store.","Monitor free disk space before saves; write failures surface as raw errno (ENOSPC/EIO) with no message."],"tags":["posix","errno","file-io","swift","darwin"],"backgroundTag":"file-read-failed","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}