Skip to content

Timeouts despite setting in config. #3708

Closed

Description

@webboty

Description

Unfortunately I am still running into timeouts when working with bigger models.
The funny thing is, it does not matter if the model is streaming or not, it just times out - see screenshot attached.

Setting in opencode as below.

 "provider": {
    "lmstudio-a" : {
      "npm": "@ai-sdk/openai-compatible",
      "name": "LM Studio (local)",
      "options": {
        "baseURL": "http://192.168.1.107:11435/v1",
        "timeout": 150000,
        "includeUsage": true,
        "apiKey": "sfgsrgg"
      },
      "models": {
        "minimax-m2": {"name": "MiniMax M2 - 5Bit MLX", "limit": {"context": 132000, "output": 16000}}
      }
    }
}

OpenCode version

0.15.31

Steps to reproduce

Make a request to a local model that is bigger in size.

Screenshot and/or share link

Image

Operating System

macOS Sonoma 14.4

Terminal

Ghostty

Activity

  1. github-actions commented on Nov 1, 2025

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  2. rekram1-node commented on Nov 1, 2025

    @rekram1-node
    Contributor

    @webboty i mean how long does it take to timeout? You could also set “timeout”: false to disable it

  3. self-assigned this
    on Nov 1, 2025
  4. webboty commented on Nov 1, 2025

    @webboty
    Author

    It took 2 minutes and 30 seconds to timeout. Interesting ... it even started streaming and was done with thinking ... was about to prepare a tool call next (i think) ... and then repeatedly after 2 minutes and 30 seconds - a hard cut with the timeout message.

    I will try setting it to false next and test again.

    Image
  5. rekram1-node commented on Nov 1, 2025

    @rekram1-node
    Contributor

    @webboty well the timeout is in milliseconds and you have it set to the equivalent of 2.5 minutes so thatd be expected

  6. webboty commented on Nov 1, 2025

    @webboty
    Author

    I set it to false and it is working.

    OMG ... of course it is milliseconds and i forgot to add another 0!
    Hmmm ... I feel stupid now and i am probably way overworked. :-|

    Thanks for your support + time and sorry for bothering.

  7. aagarin39 commented on Mar 18, 2026

    @aagarin39

    Fix: Increase chunk timeout & auto-disable for local URLs

    PROBLEM: When LLM responses take a long time (especially reasoning models like o1, Claude thinking, DeepSeek), opencode prematurely terminates the connection after 5 minutes due to DEFAULT_CHUNK_TIMEOUT = 300_000.

    SOLUTION:

    Increase default timeout from 5 to 15 minutes
    Auto-detect local URLs and disable timeout
    Allow manual override
    CODE CHANGES:

    File: packages/opencode/src/provider/provider.ts

    // Line 50-52: Increased default from 300_000 to 900_000
    // 15 minutes default chunk timeout for streaming responses
    // Increased from 5 minutes to support long-running reasoning models (o1, Claude thinking, DeepSeek, etc.)
    const DEFAULT_CHUNK_TIMEOUT = 900_000

    // Line 54-70: New function to detect local URLs
    export function isLocalURL(url: string | undefined): boolean {
    if (!url) return false
    try {
    const parsed = new URL(url)
    const hostname = parsed.hostname.toLowerCase()
    // localhost and loopback
    if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") return true
    // Private IPv4 ranges: 10.x.x.x, 172.16-31.x.x, 192.168.x.x
    if (/^(10.|172.(1[6-9]|2[0-9]|3[01]).|192.168.)/.test(hostname)) return true
    // Private IPv6 ranges (fc00::/7)
    if (/^fc00:/i.test(hostname) || /^fd[0-9a-f]{2}:/i.test(hostname)) return true
    return false
    } catch {
    return false
    }
    }

    // Line 1154-1164: Auto-detect logic
    const customFetch = options["fetch"]
    let chunkTimeout: number
    if (options["chunkTimeout"] !== undefined && options["chunkTimeout"] !== null) {
    chunkTimeout = options["chunkTimeout"] // User override
    } else {
    // Auto-detect: disable timeout for local URLs, use default for remote
    chunkTimeout = isLocalURL(baseURL) ? 0 : DEFAULT_CHUNK_TIMEOUT
    }
    delete options["chunkTimeout"]

    // Line 1170: Only create AbortController if timeout > 0
    const chunkAbortCtl = typeof chunkTimeout === "number" && chunkTimeout > 0 ? new AbortController() : undefined
    File: packages/opencode/src/config/config.ts

    // Line 1021-1029: Updated schema to allow 0
    chunkTimeout: z
    .union([
    z.number().int().min(0).describe("Timeout in milliseconds (0 to disable)."),
    z.literal(0).describe("Disable chunk timeout entirely."),
    ])
    .optional()
    .describe(
    "Timeout in milliseconds between streamed SSE chunks. Default: 900000 (15 min) for remote URLs, 0 (disabled) for local URLs (localhost, 127.x.x.x, 192.168.x.x, 10.x.x.x). Set to 0 to disable timeout.",
    ),
    File: packages/opencode/test/provider/provider.test.ts

    // Line 10-90: Unit tests for isLocalURL()
    test("isLocalURL detects localhost", () => {
    expect(Provider.isLocalURL("http://localhost:11434")).toBe(true)
    expect(Provider.isLocalURL("http://localhost:8080/v1")).toBe(true)
    })

    test("isLocalURL detects 127.0.0.1", () => {
    expect(Provider.isLocalURL("http://127.0.0.1:8080")).toBe(true)
    })

    test("isLocalURL detects private IPv4 ranges", () => {
    expect(Provider.isLocalURL("http://10.0.0.1:8080")).toBe(true)
    expect(Provider.isLocalURL("http://172.16.0.1:8080")).toBe(true)
    expect(Provider.isLocalURL("http://192.168.0.1:8080")).toBe(true)
    })

    test("isLocalURL returns false for public URLs", () => {
    expect(Provider.isLocalURL("https://api.openai.com")).toBe(false)
    expect(Provider.isLocalURL("http://8.8.8.8:8080")).toBe(false)
    })

    // Line 18-178: Integration tests
    test("chunkTimeout auto-disabled for localhost URLs", async () => {
    // Config with localhost URL
    const config = {
    provider: {
    ollama: {
    id: "llama3",
    npm: "@ai-sdk/openai-compatible",
    baseURL: "http://localhost:11434/v1",
    },
    },
    }
    // Verify chunkTimeout is 0
    expect(providers["ollama"].options.chunkTimeout).toBe(0)
    })

    test("chunkTimeout uses default for public URLs", async () => {
    // Remote URL should get 900000ms (15 min)
    expect(providers["remote"].options.chunkTimeout).toBe(900000)
    })
    CONFIGURATION EXAMPLES:

    Local server (automatic - no timeout):
    {
    "provider": {
    "ollama": {
    "baseURL": "http://localhost:11434/v1"
    }
    }
    }
    Manual override:
    {
    "provider": {
    "slow-provider": {
    "options": {
    "chunkTimeout": 0
    }
    }
    }
    }
    Custom timeout:
    {
    "provider": {
    "provider": {
    "options": {
    "chunkTimeout": 1800000
    }
    }
    }
    }
    BACKWARD COMPATIBILITY:

    Existing configs continue working
    Default increased from 5 to 15 minutes
    No breaking changes
    REQUEST FOR REVIEW:

    We'd appreciate your review of this solution:

    Minimal: Only 3 files modified, ~100 lines of code
    Safe: Fully backward compatible
    Tested: 12 new tests
    Questions:

    Is 15 minutes appropriate or should we consider 30 minutes?
    Should isLocalURL() be configurable for advanced users?
    Any concerns about the private IP detection logic?
    Looking forward to your feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions