Troubleshooting

Fix common SDK issues.

Identify the issue and find the right fix.

Check your setup

Check: Run these checks to inspect the installation, platform, and configured models.

let primordial = PrimordialClient()
let integration = try primordial.integrationStatus()
let status = await primordial.ai.status()

print(integration.sdkVersion, integration.platform, integration.isSimulator)
print(status.generation, status.embedding, status.speech)

Fix: Find the matching problem below and follow its solution.

import Primordial fails

Check: Confirm that the app target links the Primordial product.

Fix: Remove duplicate package entries, choose File > Packages > Reset Package Caches, then add the package once using Getting Started.

The project compiles but AI execution fails

Check: Confirm these requirements:

  • Xcode 26.0+ with the Swift 6.2+.
  • iOS/iPadOS 17+ or macOS 14+.
  • Physical iPhone/iPad or Apple silicon Mac for local AI.
  • Apple’s model requires OS 26+ and Apple Intelligence enabled on eligible hardware.

Fix: Run downloadable models, embeddings, and speech on a supported physical iOS device or Mac. Use the simulator only for installation and import checks.

Activation is required or rejected

Check: Print the activation error and confirm the credential and bundle identifier.

do {
    try await primordial.activate(.evaluationKey("pk_eval_..."))
} catch let error as PrimordialActivationError {
    print(error.localizedDescription)
}

Fix: Follow the matching error:

  • evaluationKeyInvalid, evaluationKeyRevoked, or evaluationKeyExpired: rotate or replace the key.
  • unregisteredAppIdentifier: register the exact, case-sensitive bundle identifier.
  • activationMetadataMissing: confirm the target has a bundle identifier and supported platform metadata.
  • activationRequestFailed: check connectivity and try again without logging the key.

See Evaluation Keys for setup instructions.

A production license is missing or rejected

Check: Activate the bundled license and print the typed error.

do {
    try await primordial.activate(.license(.bundled("Primordial.license")))
} catch let error as PrimordialActivationError {
    print(error.localizedDescription)
}

Fix: Follow the matching error:

  • licenseMissing: add Primordial.license to the app target and Copy Bundle Resources.
  • licenseMalformed, licenseInvalidSignature, licenseUnknownKey, or licenseUnsupportedVersion: download the current license again without editing it.
  • licenseWrongAppIdentifier, licenseWrongPublisherId, licenseWrongPlatform, or licenseWrongChannel: confirm the exact release identifier is registered and activate once while online.
  • licenseExpired: connect the device and activate again. Contact Primordial support if renewal remains unavailable.
  • productionLicenseRequired: replace the evaluation key with a production license in distributed builds.

Revoking a license in the console cannot remotely disable a copy already bundled in an offline app. That copy remains usable until its signed expiry and grace period end.

See Production Licenses for the complete setup.

A required capability is unavailable

Check: Inspect the workflow status and required storage.

let requirement = await primordial.ai.status(for: .answering)

print(requirement.downloadBytes)
print(requirement.requiredAvailableBytes)

Fix: Ask for download consent, then call makeAvailable for the required workflow.

for try await progress in primordial.ai.makeAvailable(.answering) {
    print(progress.phase, progress.fractionCompleted ?? 0)
}

Installation fails storage or verification

Check: Inspect the reported error and available storage.

do {
    for try await _ in primordial.ai.makeAvailable(.generation) { }
} catch PrimordialAIError.insufficientStorage(let requirement) {
    print(requirement.requiredAvailableBytes)
    print(requirement.availableBytes)
}

Fix: Follow the matching error:

  • downloadFailed: check connectivity and call makeAvailable again.
  • verificationFailed: retry once; incomplete files are never marked installed.
  • corruptedStorage: wait for active work to finish, remove the affected managed download through its matching advanced resource, then reinstall it.
try await primordial.advanced.generation.removeDownload()
for try await _ in primordial.ai.makeAvailable(.generation) { }

Use advanced.embedding or advanced.speech when those downloads are affected.

An installation was cancelled

Check: Confirm the task ended with CancellationError.

Fix: Ask for consent and call makeAvailable again. Primordial reuses completed downloads.

A model will not unload or residency failed

Check: Inspect its memory snapshot.

let value = await primordial.advanced.generation.residency()
print(value.state, value.isRetained, value.activeLeaseCount)

Fix: An active lease means work is still using the resource. A retained resource was deliberately loaded; call unload() after that work finishes. For .failed, inspect the public error and retry the intended load or unload operation. Backgrounding, Mac sleep, and memory pressure may legitimately change an unleased resource to .unloaded.

Background downloads do not finalize on iOS

Check: Confirm that the main SwiftUI scene includes Primordial's background-download modifier.

WindowGroup {
    ContentView()
}
.primordialBackgroundDownloads()

Fix: Add the modifier once. UIKit apps use the app delegate fallback shown in AI Model Setup. After a system relaunch, call the same makeAvailable capability again. A user force-quit cancels the transfer.

The Apple system model is unavailable

Check: Inspect why the system model is unavailable.

let status = await primordial.ai.status()

if case .systemUnavailable(_, let reason, let fallback) = status.generation {
    showUnavailable(reason, fallback: fallback)
}

Fix: Follow the matching reason:

  • operatingSystemNotSupported: requires OS 26+. Offer a local fallback; activate it after the user chooses it.
  • deviceNotEligible: hide the feature or offer an application-supported alternative.
  • appleIntelligenceNotEnabled: explain that the person must enable Apple Intelligence in Settings. Apps cannot enable it.
  • modelNotReady: ask the person to try later while the system prepares its model.
  • unsupportedLocale: select a supported language or offer another experience.

To offer another model, configure it explicitly in AI Model Setup.

Generation or structured output fails

Check: Match the error to the cause below.

Fix: Follow the matching error:

  • contextWindowExceeded: shorten the input, retrieved context, or conversation history and retry.
  • invalidQuery: remove empty input and correct invalid limits, categories, fields, or weights.
  • structuredOutputInvalid: try again or use a simpler schema.
  • unsupportedFeature: inspect ai.capabilities() and choose a workflow supported by the configured model.
  • invalidConfiguration: use a positive response-token limit and a finite temperature from 0 through 1.
  • generationFailed: retry when appropriate and discard partial output.

Thinking defaults: Local thinking is off when you omit generation options or use thinking: .automatic. Enable it for one local request with generationOptions: .init(thinking: .enabled). Apple Foundation Models supports per-request token and temperature options, but does not expose thinking-mode control; keep thinking: .automatic for Apple generation.

Collection indexing or search fails

Check: Confirm the data, query, and installed capabilities:

  • Keep the PrimordialClient identifier stable for the same account or workspace.
  • Use nonempty collection names, record IDs, and fields; only text fields are embedded.
  • Keep one value type per field name throughout a collection.
  • Use nonempty queries, positive limits and field weights, and filters compatible with stored field types.
  • Install .semanticSearch before synchronization, reindexing, or text search.

Fix: Correct invalid data or queries. If the index is incompatible, rebuild it:

for try await progress in notes.reindex() {
    print("Prepared:", progress.completedRecords, "/", progress.totalRecords)
    print(progress.phase, progress.fractionCompleted)
}

A pause between progress updates can mean a large record is still being prepared. Use .ready to identify completion; prepared records have not necessarily been saved yet. See reindexing progress for the upcoming per-record updates and Store & Search for collection requirements.

Collection synchronization fails

Check: Inspect the collection status and the typed error.

let status = try await notes.synchronizationStatus()

print(status.sourceIdentifier)
print(status.sourceSchemaVersion)
print(status.hasCheckpoint)
print(status.requiresSnapshot)

Fix: Follow the matching condition:

  • sourceMismatch: use the source identifier already bound to the collection, or call reset() before intentionally binding a different source.
  • sourceSchemaMismatch: use .automatic or .snapshot to build a complete snapshot after a deliberate source schema change.
  • checkpointRequired: run .automatic or .snapshot before requesting .incremental synchronization.
  • checkpointExpired or invalidCheckpoint: run .automatic to fall back to a complete snapshot, or explicitly request .snapshot.
  • invalidSynchronizationOptions: choose a batch size from 1...1000.
  • Cancellation: call synchronize(from:) again. Completed checkpoints are reused and an incomplete replacement is not exposed to search.
for try await _ in notes.synchronize(
    from: source,
    options: .init(mode: .automatic)
) { }

reset() removes the collection's searchable records, checkpoint, and source binding. Use it only when you intend to clear and rebind the collection.

SwiftData changes or removals are missing

Check: Confirm the SwiftData source requirements:

  • The source uses the same ModelContainer as the application data.
  • The encoded record ID is stable, nonempty, and unique.
  • The fetch descriptor does not contain a predicate.
  • The record ID preserves its value when the model is deleted.

Fix: Add .preserveValueOnDeletion to the stable record ID and synchronize again.

@Model
final class Note {
    @Attribute(.unique, .preserveValueOnDeletion)
    var id: UUID

    var body: String
}

Filtered SwiftData sources are not supported. Map the complete model type into a collection, then use typed collection filters when searching.

See Synchronize SwiftData for the complete setup.

Recording or transcription fails

Check: Confirm the application target includes:

  • NSMicrophoneUsageDescription
  • NSSpeechRecognitionUsageDescription
  • For a sandboxed macOS app, enable Audio Input under App Sandbox.

Fix: Add the missing permissions and enable Audio Input for sandboxed macOS apps. Install .voiceInput for file transcription and enhanced multilingual recording; microphone recording can otherwise use Apple speech recognition. After stop() or cancel(), create a new recording session. See Speech.