Ever stared at your screen, bewildered by that cryptic errordomain=nscocoaerrordomain&errormessage=ไม่พบคำสั่งลัดที่ระบุเฉพาะ&errorcode=4 message? You’re not alone. This peculiar error happens when macOS can’t locate a specific shortcut, throwing your workflow into chaos.
I’ve tackled this beast numerous times and discovered it’s not as intimidating as it looks. The Thai text in the middle translates to “specified shortcut not found”—already giving us clues about what’s gone wrong. Let’s break down this error, find its root causes, and implement battle-tested solutions to quickly get you back to coding.

What Does errordomain=nscocoaerrordomain&errormessage=ไม่พบคำสั่งลัดที่ระบุเฉพาะ&errorcode=4 Actually Mean?
This error message consists of three critical components that help diagnose the problem:
- errordomain=NSCocoaErrorDomain – Identifies that the error stems from Apple’s Cocoa framework, which handles fundamental system operations involving files, user interfaces, and application resources.
- errormessage=ไม่พบคำสั่งลัดที่ระบุเฉพาะ – The Thai text translates to “specified shortcut not found,” indicating the system couldn’t locate a particular shortcut reference.
- errorcode=4 – In the NSCocoaErrorDomain, error code 4 corresponds to “NSFileNoSuchFileError,” confirming a missing file or resource.
When debugging this error, you’ll typically see it displayed in logs or console output like this:
Error Domain=NSCocoaErrorDomain Code=4 “ไม่พบคำสั่งลัดที่ระบุเฉพาะ” UserInfo={NSLocalizedDescription=ไม่พบคำสั่งลัดที่ระบุเฉพาะ}
This error commonly appears in macOS applications that handle shortcuts, particularly when interacting with the filesystem or attempting to execute user-defined actions.

Common Causes of the NSCocoaErrorDomain Shortcut Error
1. Deleted or Moved Shortcut Files
The most frequent cause is simply that the shortcut file no longer exists where the system expects it.
// Problematic code: Hardcoded path to shortcut
let shortcutURL = URL(fileURLWithPath: “/Users/developer/Documents/Shortcuts/emailTemplate.shortcut”)
do {
let shortcutData = try Data(contentsOf: shortcutURL)
// Process shortcut data…
} catch {
print(“Error loading shortcut: \(error)”)
}
Solution:
// Improved code: Check for file existence before attempting to load
let shortcutURL = URL(fileURLWithPath: “/Users/developer/Documents/Shortcuts/emailTemplate.shortcut”)
if FileManager.default.fileExists(atPath: shortcutURL.path) {
do {
let shortcutData = try Data(contentsOf: shortcutURL)
// Process shortcut data…
} catch {
print(“Error loading shortcut: \(error)”)
}
} else {
print(“Shortcut file not found at expected location”)
// Implement recovery strategy or prompt user
}
2. Insufficient Permissions
Your app might not have proper authorization to access the shortcut file.
// Problematic code: Assuming permissions are always available
func readShortcut(at path: String) -> Data? {
return try? Data(contentsOf: URL(fileURLWithPath: path))
}
Solution:
// Improved code: Handle permission issues explicitly
func readShortcut(at path: String) -> Result<Data, Error> {
let url = URL(fileURLWithPath: path)
// Check if file exists first
guard FileManager.default.fileExists(atPath: path) else {
return .failure(NSError(domain: NSCocoaErrorDomain,
code: 4,
userInfo: [NSLocalizedDescriptionKey: “Shortcut file not found”]))
}
// Check if file is readable
guard FileManager.default.isReadableFile(atPath: path) else {
return .failure(NSError(domain: NSCocoaErrorDomain,
code: 257, // NSFileReadNoPermissionError
userInfo: [NSLocalizedDescriptionKey: “No permission to read shortcut file”]))
}
// Now try to read the file
do {
let data = try Data(contentsOf: url)
return .success(data)
} catch {
return .failure(error)
}
}
3. iCloud Sync Issues
Shortcuts synced via iCloud might become temporarily unavailable during synchronization.
// Problematic code: Not checking iCloud availability
func loadShortcut(withIdentifier identifier: String) -> Shortcut? {
let cloudURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(identifier + “.shortcut”)
guard let url = cloudURL else { return nil }
// Attempt to load from iCloud without checking download status
let data = try? Data(contentsOf: url)
return data.flatMap { Shortcut(data: $0) }
}
Solution:
// Improved code: Properly handle iCloud document state
func loadShortcut(withIdentifier identifier: String, completion: @escaping (Result<Shortcut, Error>) -> Void) {
guard let cloudURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(identifier + “.shortcut”) else {
completion(.failure(NSError(domain: NSCocoaErrorDomain, code: 4, userInfo: nil)))
return
}
// Check if file exists in local cache
if FileManager.default.fileExists(atPath: cloudURL.path) {
do {
let data = try Data(contentsOf: cloudURL)
if let shortcut = Shortcut(data: data) {
completion(.success(shortcut))
} else {
completion(.failure(NSError(domain: NSCocoaErrorDomain, code: 4, userInfo: nil)))
}
} catch {
completion(.failure(error))
}
return
}
// File not in cache, start download from iCloud
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: “%K == %@”, NSMetadataItemFSNameKey, cloudURL.lastPathComponent)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
NotificationCenter.default.addObserver(forName: .NSMetadataQueryDidFinishGathering, object: query, queue: .main) { notification in
query.disableUpdates()
defer {
query.enableUpdates()
}
guard let item = query.results.first as? NSMetadataItem else {
completion(.failure(NSError(domain: NSCocoaErrorDomain, code: 4, userInfo: nil)))
return
}
do {
try FileManager.default.startDownloadingUbiquitousItem(at: cloudURL)
// This is asynchronous, so we’ll check again after a delay
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
if FileManager.default.fileExists(atPath: cloudURL.path) {
do {
let data = try Data(contentsOf: cloudURL)
if let shortcut = Shortcut(data: data) {
completion(.success(shortcut))
} else {
completion(.failure(NSError(domain: NSCocoaErrorDomain, code: 4, userInfo: nil)))
}
} catch {
completion(.failure(error))
}
} else {
completion(.failure(NSError(domain: NSCocoaErrorDomain, code: 4, userInfo: nil)))
}
}
} catch {
completion(.failure(error))
}
}
query.start()
}
4. Corrupted Shortcut Data
Sometimes the shortcut file exists but contains invalid data.
// Problematic code: Not validating shortcut content
func parseShortcut(from data: Data) -> ShortcutAction? {
return try? JSONDecoder().decode(ShortcutAction.self, from: data)
}
Solution:
// Improved code: Implement validation and error handling
func parseShortcut(from data: Data) -> Result<ShortcutAction, Error> {
// Check minimum valid size
guard data.count > 20 else {
return .failure(NSError(domain: NSCocoaErrorDomain,
code: 4,
userInfo: [NSLocalizedDescriptionKey: “Shortcut data is incomplete or corrupted”]))
}
// Verify file signature/magic bytes (example)
let signature: [UInt8] = [0x53, 0x48, 0x43, 0x54] // “SHCT” in hex
let dataBytes = [UInt8](data.prefix(4))
guard dataBytes == signature else {
return .failure(NSError(domain: NSCocoaErrorDomain,
code: 4,
userInfo: [NSLocalizedDescriptionKey: “Invalid shortcut file format”]))
}
// Attempt to decode
do {
let action = try JSONDecoder().decode(ShortcutAction.self, from: data)
return .success(action)
} catch {
return .failure(error)
}
}
Solutions Comparison: Fixing errordomain=nscocoaerrordomain&errormessage=ไม่พบคำสั่งลัดที่ระบุเฉพาะ&errorcode=4
Prevention Techniques | Recovery Strategies |
Use dynamic path resolution instead of hardcoded paths | Implement automatic retry with fallback locations |
Implement file existence checks before access attempts | Create a recovery system that rebuilds missing shortcuts |
Request necessary permissions proactively | Provide detailed error information to help users troubleshoot |
Keep local backup copies of important shortcuts | Include step-by-step recovery instructions in your app |
Verify iCloud sync status before accessing cloud files | Implement data integrity checks with automatic repair |
Use robust error handling with specific error types | Design a user-friendly shortcut recovery interface |

How to Diagnose the NSCocoaErrorDomain Shortcut Error
When you encounter this error, follow these steps to pinpoint the exact cause:
- Enable detailed logging to capture the full error context:
// Add this early in your app’s lifecycle
func configureLogging() {
let fileLogger = FileLogger(directory: FileManager.default.temporaryDirectory, filePrefix: “ShortcutDebug”)
fileLogger.setMinimumLogLevel(.debug)
LogManager.shared.addLogger(fileLogger)
// Log all shortcut operations
LogManager.shared.debug(“Shortcut debugging enabled”)
}
// Then use throughout your code
func loadShortcut(id: String) {
LogManager.shared.debug(“Attempting to load shortcut with ID: \(id)”)
// Operation code…
if let error = result.error as NSError?,
error.domain == NSCocoaErrorDomain && error.code == 4 {
LogManager.shared.error(“Shortcut not found error: \(error.userInfo)”)
// Additional error details…
}
}
- Implement trace logging to follow the shortcut resolution path:
func resolveShortcutPath(identifier: String) -> URL? {
LogManager.shared.trace(“Starting shortcut path resolution for: \(identifier)”)
// Check user shortcuts directory
let userDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?
.appendingPathComponent(“Shortcuts”)
if let userPath = userDir?.appendingPathComponent(“\(identifier).shortcut”) {
LogManager.shared.trace(“Checking user directory path: \(userPath.path)”)
if FileManager.default.fileExists(atPath: userPath.path) {
LogManager.shared.trace(“Found shortcut at user directory”)
return userPath
}
}
// Check application support directory
let appSupportDir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?
.appendingPathComponent(“com.yourapp.shortcuts”)
if let appSupportPath = appSupportDir?.appendingPathComponent(“\(identifier).shortcut”) {
LogManager.shared.trace(“Checking application support path: \(appSupportPath.path)”)
if FileManager.default.fileExists(atPath: appSupportPath.path) {
LogManager.shared.trace(“Found shortcut at application support directory”)
return appSupportPath
}
}
// Check iCloud
if let cloudURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(“\(identifier).shortcut”) {
LogManager.shared.trace(“Checking iCloud path: \(cloudURL.path)”)
if FileManager.default.fileExists(atPath: cloudURL.path) {
LogManager.shared.trace(“Found shortcut in iCloud”)
return cloudURL
} else {
LogManager.shared.trace(“Shortcut not immediately available in iCloud, may need download”)
}
}
LogManager.shared.trace(“Shortcut not found in any location”)
return nil
}
- Create a dedicated diagnostic tool within your app:
class ShortcutDiagnosticTool {
func runFullDiagnostic(for shortcutID: String) -> DiagnosticReport {
let report = DiagnosticReport(shortcutID: shortcutID)
// Check file system
report.fileSystemChecks = performFileSystemChecks(for: shortcutID)
// Check permissions
report.permissionChecks = performPermissionChecks(for: shortcutID)
// Check database references
report.databaseChecks = performDatabaseChecks(for: shortcutID)
// Check iCloud status
report.cloudSyncChecks = performCloudSyncChecks(for: shortcutID)
return report
}
private func performFileSystemChecks(for shortcutID: String) -> [CheckResult] {
var results = [CheckResult]()
// Check each potential location
let possibleLocations = [
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?
.appendingPathComponent(“Shortcuts”)
.appendingPathComponent(“\(shortcutID).shortcut”),
FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?
.appendingPathComponent(“com.yourapp.shortcuts”)
.appendingPathComponent(“\(shortcutID).shortcut”),
FileManager.default.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(“\(shortcutID).shortcut”)
]
for (index, possibleURL) in possibleLocations.enumerated() where possibleURL != nil {
let locationName: String
switch index {
case 0: locationName = “Documents Directory”
case 1: locationName = “Application Support”
case 2: locationName = “iCloud Container”
default: locationName = “Unknown Location”
}
let exists = FileManager.default.fileExists(atPath: possibleURL!.path)
results.append(CheckResult(
name: “\(locationName) Existence Check”,
passed: exists,
details: exists ? “File found at \(possibleURL!.path)” : “File not found at \(possibleURL!.path)”
))
if exists {
// Check if it’s a regular file (not directory)
var isDir: ObjCBool = false
let isFile = FileManager.default.fileExists(atPath: possibleURL!.path, isDirectory: &isDir) && !isDir.boolValue
results.append(CheckResult(
name: “\(locationName) File Type Check”,
passed: isFile,
details: isFile ? “Path is a file” : “Path exists but is not a file”
))
// Check file size
if isFile {
do {
let attributes = try FileManager.default.attributesOfItem(atPath: possibleURL!.path)
if let fileSize = attributes[.size] as? NSNumber {
let validSize = fileSize.intValue > 0
results.append(CheckResult(
name: “\(locationName) File Size Check”,
passed: validSize,
details: validSize ? “File size: \(fileSize) bytes” : “File is empty (0 bytes)”
))
}
} catch {
results.append(CheckResult(
name: “\(locationName) File Attributes Check”,
passed: false,
details: “Could not read file attributes: \(error.localizedDescription)”
))
}
}
}
}
return results
}
// Implement other check methods similarly…
}
struct DiagnosticReport {
let shortcutID: String
let timestamp = Date()
var fileSystemChecks: [CheckResult] = []
var permissionChecks: [CheckResult] = []
var databaseChecks: [CheckResult] = []
var cloudSyncChecks: [CheckResult] = []
func generateSummary() -> String {
var summary = “Diagnostic Report for Shortcut ID: \(shortcutID)\n”
summary += “Generated: \(timestamp)\n\n”
let allChecks = fileSystemChecks + permissionChecks + databaseChecks + cloudSyncChecks
let passedChecks = allChecks.filter { $0.passed }
summary += “Summary: \(passedChecks.count)/\(allChecks.count) checks passed\n\n”
if allChecks.count – passedChecks.count > 0 {
summary += “Failed Checks:\n”
for check in allChecks where !check.passed {
summary += “❌ \(check.name): \(check.details)\n”
}
summary += “\n”
}
return summary
}
}
struct CheckResult {
let name: String
let passed: Bool
let details: String
}
Implementing a Robust Shortcut Management System
Here’s a complete, production-ready implementation of a shortcut management system that prevents and handles the errordomain=nscocoaerrordomain&errormessage=ไม่พบคำสั่งลัดที่ระบุเฉพาะ&errorcode=4 error:
import Foundation
// MARK: – Data Models
struct Shortcut: Codable {
let id: String
let name: String
let actions: [ShortcutAction]
let version: Int
let createdAt: Date
let modifiedAt: Date
}
struct ShortcutAction: Codable {
let type: ActionType
let parameters: [String: AnyCodable]
}
enum ActionType: String, Codable {
case openURL
case sendMessage
case runScript
case showNotification
// Add other action types as needed
}
// MARK: – Error Handling
enum ShortcutError: Error {
case notFound
case accessDenied
case corrupted
case invalidFormat
case cloudSyncFailed
var nsError: NSError {
switch self {
case .notFound:
return NSError(domain: NSCocoaErrorDomain, code: 4,
userInfo: [NSLocalizedDescriptionKey: “Shortcut not found”])
case .accessDenied:
return NSError(domain: NSCocoaErrorDomain, code: 257,
userInfo: [NSLocalizedDescriptionKey: “Access denied to shortcut”])
case .corrupted:
return NSError(domain: NSCocoaErrorDomain, code: 259,
userInfo: [NSLocalizedDescriptionKey: “Shortcut file is corrupted”])
case .invalidFormat:
return NSError(domain: NSCocoaErrorDomain, code: 260,
userInfo: [NSLocalizedDescriptionKey: “Invalid shortcut format”])
case .cloudSyncFailed:
return NSError(domain: NSCocoaErrorDomain, code: 4097,
userInfo: [NSLocalizedDescriptionKey: “iCloud sync failed for shortcut”])
}
}
}
// MARK: – Shortcut Manager
class ShortcutManager {
// Singleton instance
static let shared = ShortcutManager()
// Private initialization
private init() {
setupDirectories()
}
// MARK: – Properties
private let fileManager = FileManager.default
private var logger = Logger(subsystem: “com.yourapp”, category: “ShortcutManager”)
// MARK: – Directory Management
private func setupDirectories() {
do {
// Create local shortcuts directory if needed
if let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let shortcutsDirectory = documentsDirectory.appendingPathComponent(“Shortcuts”)
if !fileManager.fileExists(atPath: shortcutsDirectory.path) {
try fileManager.createDirectory(at: shortcutsDirectory, withIntermediateDirectories: true)
}
}
// Create application support directory if needed
if let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
let shortcutsDirectory = appSupportDirectory.appendingPathComponent(“com.yourapp.shortcuts”)
if !fileManager.fileExists(atPath: shortcutsDirectory.path) {
try fileManager.createDirectory(at: shortcutsDirectory, withIntermediateDirectories: true)
}
}
} catch {
logger.error(“Failed to setup directories: \(error.localizedDescription)”)
}
}
// MARK: – Shortcut Path Resolution
private func resolveShortcutPath(for id: String) -> URL? {
let potentialLocations: [URL?] = [
// Check documents directory first
fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?
.appendingPathComponent(“Shortcuts”)
.appendingPathComponent(“\(id).shortcut”),
// Check application support directory
fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?
.appendingPathComponent(“com.yourapp.shortcuts”)
.appendingPathComponent(“\(id).shortcut”),
// Check iCloud container
fileManager.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(“\(id).shortcut”)
]
// Return the first location where the file exists
for location in potentialLocations.compactMap({ $0 }) {
if fileManager.fileExists(atPath: location.path) {
return location
}
}
return nil
}
// MARK: – Save & Load Operations
func saveShortcut(_ shortcut: Shortcut, toCloud: Bool = false) -> Result<URL, Error> {
do {
// Encode the shortcut
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let data = try encoder.encode(shortcut)
// Determine save location
let saveURL: URL
if toCloud, let cloudURL = fileManager.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”) {
// Ensure cloud directory exists
if !fileManager.fileExists(atPath: cloudURL.path) {
try fileManager.createDirectory(at: cloudURL, withIntermediateDirectories: true, attributes: nil)
}
saveURL = cloudURL.appendingPathComponent(“\(shortcut.id).shortcut”)
} else {
// Save to local documents directory
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let shortcutsDirectory = documentsDirectory.appendingPathComponent(“Shortcuts”)
saveURL = shortcutsDirectory.appendingPathComponent(“\(shortcut.id).shortcut”)
}
// Write the file
try data.write(to: saveURL, options: .atomic)
// Also save a backup copy in application support
if let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
let backupDir = appSupportDirectory.appendingPathComponent(“com.yourapp.shortcuts”)
let backupURL = backupDir.appendingPathComponent(“\(shortcut.id).shortcut”)
try data.write(to: backupURL, options: .atomic)
}
logger.info(“Successfully saved shortcut: \(shortcut.id)”)
return .success(saveURL)
} catch {
logger.error(“Failed to save shortcut: \(error.localizedDescription)”)
return .failure(error)
}
}
func loadShortcut(withID id: String) -> Result<Shortcut, Error> {
guard let shortcutURL = resolveShortcutPath(for: id) else {
logger.warning(“Shortcut not found: \(id)”)
return .failure(ShortcutError.notFound)
}
do {
// Check if we have permission to read the file
guard fileManager.isReadableFile(atPath: shortcutURL.path) else {
logger.warning(“Access denied to shortcut: \(id)”)
return .failure(ShortcutError.accessDenied)
}
// Read the file data
let data = try Data(contentsOf: shortcutURL)
// Verify minimum file size
guard data.count > 20 else {
logger.warning(“Shortcut appears corrupted: \(id)”)
return .failure(ShortcutError.corrupted)
}
// Decode the shortcut
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let shortcut = try decoder.decode(Shortcut.self, from: data)
logger.info(“Successfully loaded shortcut: \(id)”)
return .success(shortcut)
} catch let decodingError as DecodingError {
logger.error(“Failed to decode shortcut: \(decodingError)”)
return .failure(ShortcutError.invalidFormat)
} catch {
logger.error(“Failed to load shortcut: \(error.localizedDescription)”)
return .failure(error)
}
}
// MARK: – Cloud Sync Operations
func syncShortcutWithCloud(id: String, completion: @escaping (Result<Shortcut, Error>) -> Void) {
guard let cloudContainer = fileManager.url(forUbiquityContainerIdentifier: nil) else {
completion(.failure(ShortcutError.cloudSyncFailed))
return
}
let cloudURL = cloudContainer.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(“\(id).shortcut”)
// Check if we have a local copy
if let localURL = resolveShortcutPath(for: id),
localURL.path != cloudURL.path {
// We have a local copy, upload it to iCloud
do {
let data = try Data(contentsOf: localURL)
// Ensure cloud directory exists
let cloudDir = cloudURL.deletingLastPathComponent()
if !fileManager.fileExists(atPath: cloudDir.path) {
try fileManager.createDirectory(at: cloudDir, withIntermediateDirectories: true)
}
// Write to cloud
try data.write(to: cloudURL)
// Load and return the shortcut
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let shortcut = try decoder.decode(Shortcut.self, from: data)
completion(.success(shortcut))
} catch {
completion(.failure(error))
}
} else {
// Check if the file exists in iCloud
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: “%K == %@”, NSMetadataItemFSNameKey, cloudURL.lastPathComponent)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
let observer = NotificationCenter.default.addObserver(
forName: .NSMetadataQueryDidFinishGathering,
object: query,
queue: .main
) { [weak self] _ in
guard let self = self else { return }
query.disableUpdates()
defer {
query.enableUpdates()
NotificationCenter.default.removeObserver(observer)
}
if let item = query.results.first as? NSMetadataItem {
do {
// Start downloading if needed
try self.fileManager.startDownloadingUbiquitousItem(at: cloudURL)
// Check file status after a delay
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
if self.fileManager.fileExists(atPath: cloudURL.path) {
self.loadShortcut(withID: id).map { shortcut in
completion(.success(shortcut))
}.mapError { error in
completion(.failure(error))
}
} else {
completion(.failure(ShortcutError.notFound))
}
}
} catch {
completion(.failure(error))
}
} else {
completion(.failure(ShortcutError.notFound))
}
}
query.start()
}
}
// MARK: – Recovery Operations
func recoverShortcut(withID id: String) -> Result<Shortcut?, Error> {
// Try to recover from backup first
if let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
let backupDir = appSupportDirectory.appendingPathComponent(“com.yourapp.shortcuts”)
let backupURL = backupDir.appendingPathComponent(“\(id).shortcut”)
if fileManager.fileExists(atPath: backupURL.path) {
do {
let data = try Data(contentsOf: backupURL)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let shortcut = try decoder.decode(Shortcut.self, from: data)
// Restore to primary location
if let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let shortcutsDirectory = documentsDirectory.appendingPathComponent(“Shortcuts”)
let primaryURL = shortcutsDirectory.appendingPathComponent(“\(id).shortcut”)
try data.write(to: primaryURL)
logger.info(“Successfully recovered shortcut from backup: \(id)”)
return .success(shortcut)
}
} catch {
logger.error(“Backup recovery failed: \(error.localizedDescription)”)
// Continue to other recovery methods
}
}
}
// Try to recover from iCloud if backup failed
if let cloudURL = fileManager.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(“\(id).shortcut”),
fileManager.fileExists(atPath: cloudURL.path) {
do {
let data = try Data(contentsOf: cloudURL)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let shortcut = try decoder.decode(Shortcut.self, from: data)
// Restore to primary location
if let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let shortcutsDirectory = documentsDirectory.appendingPathComponent(“Shortcuts”)
let primaryURL = shortcutsDirectory.appendingPathComponent(“\(id).shortcut”)
try data.write(to: primaryURL)
logger.info(“Successfully recovered shortcut from iCloud: \(id)”)
return .success(shortcut)
}
} catch {
logger.error(“iCloud recovery failed: \(error.localizedDescription)”)
}
}
// No recovery options successful
return .success(nil)
}
// MARK: – Testing Utilities
func testShortcutAccess(id: String) -> [String: Bool] {
var results = [String: Bool]()
// Test if shortcut exists anywhere
results[“exists”] = resolveShortcutPath(for: id) != nil
// Test specific locations
if let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let shortcutsDirectory = documentsDirectory.appendingPathComponent(“Shortcuts”)
let primaryURL = shortcutsDirectory.appendingPathComponent(“\(id).shortcut”)
results[“existsInDocuments”] = fileManager.fileExists(atPath: primaryURL.path)
if results[“existsInDocuments”] == true {
results[“readableInDocuments”] = fileManager.isReadableFile(atPath: primaryURL.path)
}
}
if let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
let backupDir = appSupportDirectory.appendingPathComponent(“com.yourapp.shortcuts”)
let backupURL = backupDir.appendingPathComponent(“\(id).shortcut”)
results[“existsInAppSupport”] = fileManager.fileExists(atPath: backupURL.path)
if results[“existsInAppSupport”] == true {
results[“readableInAppSupport”] = fileManager.isReadableFile(atPath: backupURL.path)
}
}
if let cloudURL = fileManager.url(forUbiquityContainerIdentifier: nil)?
.appendingPathComponent(“Documents/Shortcuts”)
.appendingPathComponent(“\(id).shortcut”) {
results[“existsInCloud”] = fileManager.fileExists(atPath: cloudURL.path)
if results[“existsInCloud”] == true {
results[“readableInCloud”] = fileManager.isReadableFile(atPath: cloudURL.path)
}
} else {
results[“cloudAvailable”] = false
}
return results
}
}
// MARK: – Utility Extensions
extension Result {
func mapError<NewFailure: Error>(_ transform: (Failure) -> NewFailure) -> Result<Success, NewFailure> {
switch self {
case .success(let value):
return .success(value)
case .failure(let error):
return .failure(transform(error))
}
}
}
// A utility class to handle “Any” type in Codable
struct AnyCodable: Codable {
private let value: Any
init(_ value: Any) {
self.value = value
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self.value = NSNull()
} else if let bool = try? container.decode(Bool.self) {
self.value = bool
} else if let int = try? container.decode(Int.self) {
self.value = int
} else if let double = try? container.decode(Double.self) {
self.value = double
} else if let string = try? container.decode(String.self) {
self.value = string
} else if let array = try? container.decode([AnyCodable].self) {
self.value = array.map { $0.value }
} else if let dictionary = try? container.decode([String: AnyCodable].self) {
self.value = dictionary.mapValues { $0.value }
} else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: “AnyCodable value cannot be decoded”)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self.value {
case is NSNull:
try container.encodeNil()
case let bool as Bool:
try container.encode(bool)
case let int as Int:
try container.encode(int)
case let double as Double:
try container.encode(double)
case let string as String:
try container.encode(string)
case let array as [Any]:
try container.encode(array.map { AnyCodable($0) })
case let dictionary as [String: Any]:
try container.encode(dictionary.mapValues { AnyCodable($0) })
default:
throw EncodingError.invalidValue(self.value, EncodingError.Context(
codingPath: container.codingPath,
debugDescription: “AnyCodable value cannot be encoded”
))
}
}
}
// Simplified logger for the example
struct Logger {
let subsystem: String
let category: String
func info(_ message: String) {
print(“[\(subsystem):\(category)] INFO: \(message)”)
}
func warning(_ message: String) {
print(“[\(subsystem):\(category)] WARNING: \(message)”)
}
func error(_ message: String) {
print(“[\(subsystem):\(category)] ERROR: \(message)”)
}
}

Unit Tests to Validate Your Error Handling
Here’s how you can create comprehensive tests to ensure your code properly handles the shortcut error:
import XCTest
@testable import YourAppModule
class ShortcutErrorHandlingTests: XCTestCase {
var shortcutManager: ShortcutManager!
var tempDirectory: URL!
override func setUp() {
super.setUp()
shortcutManager = ShortcutManager.shared
// Create a temporary directory for testing
tempDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
try! FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true)
}
override func tearDown() {
// Clean up temp directory
try? FileManager.default.removeItem(at: tempDirectory)
super.tearDown()
}
func testShortcutNotFoundError() {
// Attempt to load a non-existent shortcut
let result = shortcutManager.loadShortcut(withID: “non-existent-id”)
// Verify we get the correct error
switch result {
case .failure(let error as ShortcutError):
XCTAssertEqual(error, ShortcutError.notFound)
let nsError = error.nsError
XCTAssertEqual(nsError.domain, NSCocoaErrorDomain)
XCTAssertEqual(nsError.code, 4)
default:
XCTFail(“Expected .failure with ShortcutError.notFound, got \(result)”)
}
}
func testPermissionError() {
// Create a shortcut file with restricted permissions
let shortcutID = “permission-test”
let shortcutPath = tempDirectory.appendingPathComponent(“\(shortcutID).shortcut”)
// Create a test shortcut
let shortcut = createTestShortcut(id: shortcutID)
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let data = try! encoder.encode(shortcut)
try! data.write(to: shortcutPath)
// Modify permissions to make it unreadable
try! FileManager.default.setAttributes([.posixPermissions: 0], ofItemAtPath: shortcutPath.path)
// Mock the resolution path to return our permission-restricted file
let originalResolveMethod = shortcutManager.resolveShortcutPath
shortcutManager.resolveShortcutPath = { _ in return shortcutPath }
// Attempt to load the shortcut
let result = shortcutManager.loadShortcut(withID: shortcutID)
// Restore original method
shortcutManager.resolveShortcutPath = originalResolveMethod
// Verify we get the correct error
switch result {
case .failure(let error as ShortcutError):
XCTAssertEqual(error, ShortcutError.accessDenied)
default:
XCTFail(“Expected .failure with ShortcutError.accessDenied, got \(result)”)
}
}
func testCorruptedShortcutError() {
// Create a shortcut file with invalid data
let shortcutID = “corrupted-test”
let shortcutPath = tempDirectory.appendingPathComponent(“\(shortcutID).shortcut”)
// Write invalid data
let invalidData = Data([0, 1, 2, 3]) // Too small to be a valid shortcut
try! invalidData.write(to: shortcutPath)
// Mock the resolution path to return our corrupted file
let originalResolveMethod = shortcutManager.resolveShortcutPath
shortcutManager.resolveShortcutPath = { _ in return shortcutPath }
// Attempt to load the shortcut
let result = shortcutManager.loadShortcut(withID: shortcutID)
// Restore original method
shortcutManager.resolveShortcutPath = originalResolveMethod
// Verify we get the correct error
switch result {
case .failure(let error as ShortcutError):
XCTAssertEqual(error, ShortcutError.corrupted)
default:
XCTFail(“Expected .failure with ShortcutError.corrupted, got \(result)”)
}
}
func testInvalidFormatError() {
// Create a shortcut file with valid data but wrong format
let shortcutID = “format-test”
let shortcutPath = tempDirectory.appendingPathComponent(“\(shortcutID).shortcut”)
// Write valid JSON but not a valid shortcut
let invalidFormat = “””
{
“type”: “wrong-format”,
“data”: “This is not a shortcut”
}
“””.data(using: .utf8)!
try! invalidFormat.write(to: shortcutPath)
// Mock the resolution path to return our invalid format file
let originalResolveMethod = shortcutManager.resolveShortcutPath
shortcutManager.resolveShortcutPath = { _ in return shortcutPath }
// Attempt to load the shortcut
let result = shortcutManager.loadShortcut(withID: shortcutID)
// Restore original method
shortcutManager.resolveShortcutPath = originalResolveMethod
// Verify we get the correct error
switch result {
case .failure(let error as ShortcutError):
XCTAssertEqual(error, ShortcutError.invalidFormat)
default:
XCTFail(“Expected .failure with ShortcutError.invalidFormat, got \(result)”)
}
}
func testRecoveryFromBackup() {
// Create a shortcut and its backup
let shortcutID = “recovery-test”
// Create a test shortcut
let shortcut = createTestShortcut(id: shortcutID)
// Save to backup location
let backupDir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
.appendingPathComponent(“com.yourapp.shortcuts”)
try! FileManager.default.createDirectory(at: backupDir, withIntermediateDirectories: true)
let backupURL = backupDir.appendingPathComponent(“\(shortcutID).shortcut”)
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let data = try! encoder.encode(shortcut)
try! data.write(to: backupURL)
// Now test recovery
let result = shortcutManager.recoverShortcut(withID: shortcutID)
// Verify recovery worked
switch result {
case .success(let recoveredShortcut):
XCTAssertNotNil(recoveredShortcut)
XCTAssertEqual(recoveredShortcut?.id, shortcutID)
case .failure:
XCTFail(“Recovery should have succeeded”)
}
// Verify the shortcut was restored to primary location
let primaryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
.appendingPathComponent(“Shortcuts”)
.appendingPathComponent(“\(shortcutID).shortcut”)
XCTAssertTrue(FileManager.default.fileExists(atPath: primaryURL.path))
}
// Helper method to create a test shortcut
private func createTestShortcut(id: String) -> Shortcut {
return Shortcut(
id: id,
name: “Test Shortcut”,
actions: [
ShortcutAction(
type: .openURL,
parameters: [“url”: AnyCodable(“https://example.com”)]
)
],
version: 1,
createdAt: Date(),
modifiedAt: Date()
)
}
}
Conclusion
The errordomain=nscocoaerrordomain&errormessage=ไม่พบคำสั่งลัดที่ระบุเฉพาะ&errorcode=4 error may seem cryptic, but it’s fundamentally a file not found issue with a specific context: macOS can’t locate a shortcut you’re trying to use. By implementing proactive file system checks, maintaining backup copies, and using graceful error handling, you can prevent this error from disrupting your users’ experience.
The most important takeaway? Never access shortcuts without first verifying their existence and readability. This single practice prevents shortcut-related errors and creates a significantly more robust application.