Skip to content

iOS 26.5.x: file operations on --app-group containers fail device-side with RemoteServices 11007 "File paths cannot contain '..'" (paths contain no '..'); file ls hangs silently; failed pull leaves zero-byte local file #784

Description

@bitjson

Root cause is an Apple issue, but dropping this here in case the go-ios suggestions are useful.

(Fable 5:)

Summary

On devices running iOS 26.5.2, ios file pull --app-group=<groupID> fails for app-created files in the App Group container with a device-side error:

code 11007, File paths cannot contain '..'.

although neither the submitted relative path nor the device-resolved absolute path contains ... ios file ls --app-group=… (root or any subdirectory) hangs indefinitely with no output. The same operations against the app's own data container (--app=<bundleID>) work fine on the same devices and tunnels.

This does not appear to be a go-ios framing bug — I verified that Apple's own xcrun devicectl (518.33, Xcode 26.6, macOS 26.5.2 host, freshly paired) fails identically on the same paths, and go-ios sends the caller's path verbatim (ios/fileservice/fileservice.go:178-182). The rejection happens on the device after correct container resolution: the device's encoded error names the fully-resolved absolute container path, and its UUID matches what the app itself reports from containerURL(forSecurityApplicationGroupIdentifier:). Reproduced identically on three devices (iPhone 15 Pro Max, iPhone 16 Pro, iPhone 16 Pro Max, all iOS 26.5.2), across two independent client stacks (go-ios's own tunnel/RemoteXPC and Apple's CoreDevice). Filing here because --app-group is an advertised go-ios capability that is currently unusable on iOS 26.5.x, and because two go-ios-side behaviors around the failure could be hardened (see "Suggested improvements").

Reproduction

Requires: a macOS or Linux host with go-ios v1.2.0 (also current main @ 274bc43 — the fileservice code is unchanged since PR #642), an iOS 26.5.x device in developer mode, and any dev app entitled with an App Group.

  1. In the app, create nested content in the App Group container and print the root:

    let fm = FileManager.default
    let root = fm.containerURL(forSecurityApplicationGroupIdentifier: "group.example.sync")!
    let dir = root.appendingPathComponent("shared-data/sub/dataset-a", isDirectory: true)
    try fm.createDirectory(at: dir, withIntermediateDirectories: true)
    try Data(#"{"hello":"world"}"#.utf8).write(to: dir.appendingPathComponent("manifest.json"))
    print("app group root:", root.path)   // e.g. /private/var/mobile/Containers/Shared/AppGroup/<UUID>
  2. Start the tunnel and try to read the file back:

    sudo ios tunnel start                       # separate terminal, keep running
    
    ios file ls   --app-group=group.example.sync --path=.
    # ACTUAL: no output, no error — blocks until externally killed (observed >20s on every attempt,
    #         root and subdirectories alike)
    
    ios file pull --app-group=group.example.sync \
      --remote=shared-data/sub/dataset-a/manifest.json --local=/tmp/manifest.json
    # ACTUAL: fails with the device-relayed EncodedError: code 11007,
    #         LocalizedDescription "File paths cannot contain '..'.",
    #         NSFilePath = /private/var/mobile/Containers/Shared/AppGroup/<UUID>/shared-data/sub/dataset-a/manifest.json
    #         (the CORRECT resolved path — same <UUID> the app printed in step 1; no '..' anywhere)
    # ACTUAL: /tmp/manifest.json exists afterwards with size 0
    

    Expected: the listing returns entries (or a typed error), and the pull streams the file.

  3. Cross-check with Apple's client — same device-side rejection, so the daemon, not go-ios:

    xcrun devicectl device copy from --device <udid> \
      --domain-type appGroupDataContainer --domain-identifier group.example.sync \
      --source shared-data/sub/dataset-a/manifest.json --destination /tmp/manifest-devicectl.json
    
    "error" : {
      "code" : 7000, "domain" : "com.apple.dt.CoreDeviceError",
      "userInfo" : { "NSLocalizedDescription" : { "string" : "The specified file could not be transferred." },
        "NSUnderlyingError" : { "error" : {
          "code" : 11007, "domain" : "com.apple.dt.remoteservices.error",
          "userInfo" : {
            "NSFilePath" : { "string" : "/private/var/mobile/Containers/Shared/AppGroup/<UUID>/shared-data/sub/dataset-a/manifest.json" },
            "NSLocalizedDescription" : { "string" : "File paths cannot contain '..'." } } } } } }

    Two more devicectl data points that localize the fault device-side:

    • Root listing succeeds but is content-false: devicectl device info files --domain-type appGroupDataContainer --domain-identifier group.example.sync --subdirectory "" returns only the container-provisioning skeleton (Library, Library/Caches, Library/Preferences) even though the app sees its own directories in the same container (same UUID).
    • Subdirectory listing fails: --subdirectory shared-dataCoreDevice.ActionError code 3, "StreamingAction: The system failed to get a list of files on the remote device."
    • Control: the same copy from against --domain-type appDataContainer --domain-identifier <bundleID> succeeds on the same device/session (multi-KB files verified).

    Ruled out on the environment side: host/device OS skew (host 26.5.2 ≥ device 26.5.2 — note that an older host macOS breaks ALL file StreamingActions in both domains, a separate failure mode worth knowing when triaging reports), stale pairing (fresh re-pair), wedged daemons (verified restarts of remoted/CoreDeviceService, device reboots — no change), stale tunnel (fresh go-ios tunnel), dotfiles-only (plain manifest.json fails identically), and a .. in the local destination filename (go-ios legs used clean destinations).

Analysis

  • go-ios sends the path verbatim: ios/fileservice/fileservice.go:178-182 (RetrieveFile request); the session for Domain 2 (DomainAppGroupDataContainer) is created successfully (fileservice.go:84-116), and the 11007 arrives in the control response's EncodedError, relayed by extractError (fileservice.go:422-433). Nothing client-side can introduce ...
  • The device rejects after resolving the correct container, before any data streaming (the data service is never engaged). The error message is factually wrong for the path — it looks like a device-side path-containment/canonicalization check inside the CoreDevice fileservice that fires on App Group paths below the container root and reports its generic .. message. The skeleton-only root listing suggests the service's view of App Group containers doesn't include app-created content at all on iOS 26.5.x.
  • I could not establish that this ever worked on earlier iOS versions — treat "regression vs never-worked" as open. A Feedback Assistant report to Apple is being considered in parallel; filing here so go-ios users searching this error find a tracked issue.

Suggested improvements (go-ios side, independent of Apple's fix)

  1. ListDirectory should not hang forever (ios/fileservice/fileservice.go:120-168): it blocks in ReceiveOnClientServerStream() (:138) with no timeout. Note every other control response (CreateSession, RetrieveFile, ProposeFile) is received on the ServerClient stream — if the device reports a RetrieveDirectoryList failure on the control stream, the error is silently lost and file ls blocks indefinitely, which matches what I observed (devicectl returns a typed StreamingAction error for the same request; go-ios produces nothing). A receive timeout plus checking the control stream for an EncodedError would turn an infinite hang into a diagnosable failure.
  2. Don't leave zero-byte files on failed pulls (cmd_device_files.go:118-123): os.Create(localPath) runs before PullFile, so every failed pull leaves a 0-byte destination that scripted pipelines can mistake for a successful empty file. Create after the RetrieveFile control response succeeds, or unlink on error.
  3. Document the iOS 26.5.x App Group limitation (README / ios file help) while it persists, since users will hit the misleading .. error and reasonably assume a go-ios path-handling bug.

Workaround

App-side staging: have the app (which sees the App Group container normally) copy or serialize the needed files into its own data container (e.g. Documents/), then ios file pull --app=<bundleID> --remote=Documents/… --local=… — the appDataContainer domain is unaffected. Verified working on the same devices while the App Group domain fails.

Versions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions